Filed under Testing

When will we ever see something like this in MSTest?

Perhaps I haven’t looked enough but I really miss Assert.Throws in MSTest. Or does it exist? I’ve seen more people look for it…. For me, I just put together something real quick.

[DebuggerStepThrough()]
public static T Throws<T>(Action action) where T : Exception
{
    try
    {
        action.Invoke();
    }
    catch (T ex)
    {
        return ex;
    }
    catch (Exception ex)
    {
        throw new AssertFailedException(
            string.Format("Expected exception was not thrown! Got other exception: '{0}'.", ex.GetType())
            ,ex);
    }

    throw new AssertFailedException("Expected exception was not thrown! None was thrown.");
}

//Daniel

Tagged ,

Why the ExpectedExceptionAttribute sucks!

Today I was reading a book which showed an example of an unit test. And even if it was just there to show unit testing as a concept when doing ASP.Net MVC development, I really think you never, ever, ever, ever, ever…..(n)….ever should use that ugly attribute. Why, well follow along.

BTW, the example tests below is not as they were in the book and they are just created for showing you the fragility of ExpectedExceptionAttribute

Test 1: Place a bid When no bids exists Then the bid gets added

You should be able to place a bid when no other bid exists, then there should be one bid registrered and that is the one you placed.

Test

[Test]
public void PlaceBid_WhenNoBidsExists_BidIsAdded()
{
    const int artefactId = 1;
    const decimal bid = 100m;

    var auction = new Auction();
    auction.PlaceBid(artefactId, bid);

    var bids = auction.GetBids(artefactId);
    Assert.AreEqual(bid, bids.Single());
}

Implementation

public class Auction
{
    private readonly Dictionary<int, List<decimal>> _bids
         = new Dictionary<int, List<decimal>>();

    public void PlaceBid(int artefactId, decimal bid)
    {
        _bids.Add(artefactId, new List<decimal> { bid });
    }

    public IEnumerable<decimal> GetBids(int artefactId)
    {
        if (!_bids.ContainsKey(artefactId))
            return Enumerable.Empty<decimal>();

        return _bids[artefactId];
    }
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

1 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Ok, nothing complicated here, lets move on to the next test.

Test 2: Place a bid When a higher bid exists Then it throws an InvalidOperationException

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 10m);
    auction.PlaceBid(artefactId, 5m);
}

Implementation

public void PlaceBid(int artefactId, decimal bid)
{
    var hasExistingExceedingBid = GetBids(artefactId)
        .Any(existingBid => existingBid >= bid);

    if (hasExistingExceedingBid)
        throw new InvalidOperationException(
            "The bid is to low. Existing bids with same or higher value exists.");

    _bids.Add(artefactId, new List<decimal> { bid });
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

2 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Ok, everything works and the ExpectedException is thrown and the second test passes. Lets continue and add yet another test to meet a new requirement.

Test 3: Place a bid When the bid is lower than five Then it throws an InvalidOperationException

Just by readint the test spec there should be an alarm bell going of here. I will give you a small hint: … Then it throws an InvalidOperationException. Two tests for different requirements throws the same exception. What could go wrong? Lets see. Lets continue our journey.

Test

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void PlaceBid_WhenBidIsLowerThan5_ThrowsInvalidOperationException()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 4m);
}

Implementation

public void PlaceBid(int artefactId, decimal bid)
{
    if (bid < 5)
        throw new InvalidOperationException(
            "The bid is to low. A bid must be greater than 5.");

    var hasExistingExceedingBid = GetBids(artefactId)
        .Any(existingBid => existingBid >= bid);

    if (hasExistingExceedingBid)
        throw new InvalidOperationException(
            "The bid is to low. Existing bids with same or higher value exists.");

    _bids.Add(artefactId, new List<decimal> { bid });
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

3 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Ok, still everything works out fine, or does it?

A change of the requirements – instead of check against bid lower than five, ten should be used

Piece of cake. Just update the test PlaceBid_WhenBidIsLowerThan5_ThrowsInvalidOperationException and make it fail and correct the implementation so that we get a green test for the new requirement.

Test

[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void PlaceBid_WhenBidIsLowerThan10_ThrowsInvalidOperationException()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 9m); //UPDATED
}

Implementation

public void PlaceBid(int artefactId, decimal bid)
{
    if (bid < 10) //UPDATED
        throw new InvalidOperationException(
            "The bid is to low. A bid must be greater than 10."); //UPDATED

    var hasExistingExceedingBid = GetBids(artefactId)
        .Any(existingBid => existingBid >= bid);

    if (hasExistingExceedingBid)
        throw new InvalidOperationException(
            "The bid is to low. Existing bids with same or higher value exists.");

    _bids.Add(artefactId, new List<decimal> { bid });
}

Result

------ Test started: Assembly: ClassLibrary1.dll ------

3 passed, 0 failed, 0 skipped, took 0,14 seconds (NUnit 2.5.5).

Three tests passes. How about that! Nothing wrong there is it? Of course. Lets tweak the test that checks if there’s any existing bids that are higher.

Updated test #1

[Test]
[ExpectedException(
    typeof(InvalidOperationException),
    ExpectedMessage = "The bid is to low. Existing bids with same or higher value exists.")]
public void PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better1()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 10m);
    auction.PlaceBid(artefactId, 5m);
}

I have now put an expectation on the message, now lets see what happens.

------ Test started: Assembly: ClassLibrary1.dll ------

Test 'ClassLibrary1.AuctionTests.PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better1' failed: The exception message text was incorrect
Expected: The bid is to low. Existing bids with same or higher value exists.
 but was: The bid is to low. A bid must be greater than 10.
	BidTests.cs(80,0): at ClassLibrary1.Auction.PlaceBid(Int32 artefactId, Decimal bid)
	BidTests.cs(56,0): at ClassLibrary1.AuctionTests.PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better1()

3 passed, 1 failed, 0 skipped, took 0,20 seconds (NUnit 2.5.5).

The exception message text was incorrect
Expected: The bid is to low. Existing bids with same or higher value exists.
but was: The bid is to low. A bid must be greater than 10.

How about that! The exception was thrown at the wrong place. Of course this situation could have been avoided with some specific business exception or even an ArgumentOutOfRangeException; but again. This is a simplified, fictive scenario which still isn’t making me happy, since the ugly ExpectedExceptionAttribute still is present. Lets fix that.

Assert.Throws

Moste testing frameworks (NOT MSTest) has some sort of ability to pass a delegate to a method and the lets you specify that you expect that delegate to throw an exception of a certain type. If the exception isn’t thrown, the test fails.

For you MSTest users, you can of course write this test util on your own.

Updated test #2

[Test]
public void PlaceBid_WhenHigherBidExists_ThrowsInvalidOperationException_Better2()
{
    const int artefactId = 1;
    var auction = new Auction();

    auction.PlaceBid(artefactId, 10m);

    var ex = Assert.Throws<InvalidOperationException>(
        () => auction.PlaceBid(artefactId, 5m));

    Assert.AreEqual(
        "The bid is to low. Existing bids with same or higher value exists.",
        ex.Message);
}

I hope you get the point, and that you stop using the not so nifty ExpectedExceptionAttribute

//Daniel

Tagged ,

Who is the unit and integration tests for?

The unit tests and integration tests are for the developers. And not only for the developer working with the item being implemented, but all the developers currently in the team; and all the developers that will join the team in the future. The unit tests and integration tests are not for the customer, they are there to give the developers a safety net; there to specify the intent of the code; there to embrace quality. I would go so far to say:

a customer should never question the existance of tests, only the lack of them

Isn’t unit tests enough?

No! If you would have to select one, integrations tests is the way I would go. Why? Well I guess you don’t plan to let every piece of your code run in isolation and never integrate with other parts of your’s or other’s systems. I also guess you intend to have some sort of persistence in your system, like a database. If you don’t do integration tests and regression tests, how would you know that

implementation or change of feature X doesn’t brake feature Y

Why don’t you write tests?

One thing is for sure: “since you aren’t testdriven”. I’m not going to state that you must be testdriven to succeed, but it shure does help.

Not having a good suite of tests make me feel like an electrician working with high voltage without knowing if the power is on or off

To the customer

If you are the reason for not writing tests and you instead rely on manual testing, how much does the/these tester/s doing manual arbitrary testing cost and how much coverage do you gain from those testers?

To the developer

How does it feel to be blamed when you push some changes and a new version of the software is shipped and shortly after (hopefully) the customer or user comes with an error report:

Hey, this thing just stopped working but it worked a hour ago. How can that be? Don’t you test your stuff before releasing them?

They are for all!

The tests are mainly for the team but the effect of them provides benefits for all. For the customer and the users and the families to all involved stakeholders, since they get happy relatives coming home from job. Enough said.

//Daniel

Tagged ,

Tip – When writing custom assertion methods – Keep your assertion stack trace clean

I have bumped in to a couple of custom assertion methods which lets the assertion stack trace contain the assertion method itself. Hence, if I use, e.g. Testdriven.Net, I might double-click on the wrong line and end up in the assertion method, instead of the test. It’s really easy to prevent this, just add the DebuggerHiddenAttribute (read more) to the assertion method.

Example

First, lets be clear. The taken example is not realistic and there’s already support for array assertions but lets pretend I want an assertion method that asserts string arrays and ensures that:

  • the number of elements are the same
  • the order of the elements are the same

I’m using Galio, MbUnit and Testdriven.net

The test

[TestFixture]
public class DummyTests
{
    [Test]
    public void GetAsSortedStringArray_WhenManyParams_ReturnsSortedStringArray()
    {
        var values = new int[] {0, 4, 5, 1, 3, 2};
        var expectedResult = new[] {"0", "-1", "2", "3", "4", "5"};

        var dummy = new Dummy();
        var sortedStringArray = dummy.GetAsSortedStringArray(values);

        ArrayAssert.AreMatches(expectedResult, sortedStringArray);
    }
}

The test will fail (which is expected in this blogpost) since The expected element number "2" should have value "1" and not "-1"

What is wrong with the test

The implementation of Dummy

public class Dummy
{
    public string[] GetAsSortedStringArray(params int[] values)
    {
        return values.Select(v => v.ToString()).OrderBy(v => v).ToArray();
    }
}

The Assertion method

public static class ArrayAssert
{
    public static void AreMatches(string[] expectedValues, string[] actualValues)
    {
        var numOfExpected = expectedValues.Count();
        var numOfActual = actualValues.Count();

        if (numOfExpected != numOfActual)
            throw new AssertionException(string.Format(
                @"The expected values and the actual values have 
                different number of elements.
                Expected: '{0}'; Actual: '{1}'.", numOfExpected, numOfActual));

        for(var c = 0; c < numOfExpected; c++)
        {
            var expected = expectedValues[c];
            var actual = actualValues[c];

            if(!expected.Equals(actual))
                throw new AssertionException(string.Format(
                    @"The values in element-position '{0}' are not the same.
                    Expected: '{1}'; Actual: '{2}'.", c, expected ?? "", actual ?? ""));
        }
    }
}

What’s wrong?

The result of the assertion will be:

Testdriven.Net – Result
Testdriven.Net - Result - Not friendly

Gallio – Result
Gallio - Result - Not friendly

I have tried to mark the lines that I think pollutes the result. It’s the lines stating something like:

Class1.cs(44,0): at ClassLibrary1.ArrayAssert.AreMatches(String[] expectedValues, String[] actualValues)

This is not of interest. And by adding the attribute DebuggerHidden I will get another assertion result, which in my opinion is slightly more friendly.

The corrected assertion method

public static class ArrayAssert
{
    [DebuggerHidden]
    public static void AreMatches(string[] expectedValues, string[] actualValues)
    {
        ...
    }
}

More friendly assertion result

Testdriven.Net – Result
Testdriven.Net - Results - Friendly

Gallio – Result
Gallio - Results - Friendly

Nothing more to say.

//Daniel

Tagged , , ,

Moq vs Typemock – Simple solution to It.Is(expression)

So I thought I just add one more post about this subject. Previous posts:

As I stated I don’t like the predicate that gives me an object[0], so why not do something about it.

public static class IArgumentsMatcherExtensions
{
    public static void Matching<T>(this IArgumentsMatcher matcher, Predicate<T> verify)
    {
        matcher.Matching(args => verify.Invoke((T)args[0]));
    }
}

With this code I can now write tests like:

[Test, Isolated]
public void TheTest3()
{
    var args = new MyArgsWithoutEquals();
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();
    fake.MyMethod(args);

    Isolate.Verify.WasCalledWithArguments(
        () => fake.MyMethod(args)).Matching<IMyArgs>(a1 => a1.Id == 1);
}

Instead of

[Test]
public void TheTest4()
{
    var args = new MyArgsWithoutEquals();
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();
    fake.MyMethod(args);

    Isolate.Verify.WasCalledWithArguments(
        () => fake.MyMethod(args)).Matching(x => ((IMyArgs)x[0]).Id == 1);
}

I hope I will see something like this in Typemock in the future.

//Daniel

Tagged

Moq vs TypeMock – Simple solution to It.IsAny

So I just posted this post where I wanted the It.IsAny syntax in Typemock. Without giving any long thought on this I wrote two simple solutions:

Solution 1

public static class IVerifyHandlerExtensions
{
    public static void WasCalledWithAnyArguments<T>(this IVerifyHandler handler, Action<T> action)
    {
        handler.WasCalledWithAnyArguments(() => action.Invoke(default(T)));
    }
}

[Test, Isolated]
public void TheTest()
{
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();
    fake.MyMethod(new MyArgsWithoutEquals());

    Isolate.Verify.WasCalledWithAnyArguments<MyArgsWithoutEquals>(fake.MyMethod);
}

Solution 2

public static class IsAny<T>
{
    public static T Item = default(T);
}

[Test, Isolated]
public void TheTest2()
{
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();
    fake.MyMethod(new MyArgsWithoutEquals());

    Isolate.Verify.WasCalledWithAnyArguments(() => fake.MyMethod(IsAny<IMyArgs>.Item));
}

As I said. Not much thinking in there so I’m probably missing something. It worked for me. Now I don’t have to type “null” any more.

//Daniel

Tagged

Moq vs Typemock – It.IsAny & It.Is

I kind of like the It.IsAny syntax and It.IsAny(validation expression) syntax of Moq. So now when I’m in the process of switching to Typemock I really was looking for this kind of API.

I have put together some simple samples to show the difference.

The difference in the APIs

#1

[Test]
public void VerifyCallWithExplicitArguments_WhenSameInstanceArgs_VerifiesOk()
{
    var args = new MyArgsWithoutEquals();
    var fake = new Mock<MyClassUnderTest>();

    var invoker = new Invoker(fake.Object);
    invoker.Invoke(args);

    fake.Verify(f => f.MyMethod(args));
}

[Test, Isolated]
public void VerifyCallWithExplicitArguments_WhenSameInstanceArgs_VerifiesOk()
{
    var args = new MyArgsWithoutEquals();
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();

    var invoker = new Invoker(fake);
    invoker.Invoke(args);

    Isolate.Verify.WasCalledWithExactArguments(
        () => fake.MyMethod(args));
}

#2

[Test]
public void VerifyCallWithExplicitArguments_WhenOtherInstanceArgs_ThrowsMockException()
{
    var args = new MyArgsWithoutEquals();
    var argsOther = new MyArgsWithoutEquals();
    var fake = new Mock<MyClassUnderTest>();

    var invoker = new Invoker(fake.Object);
    invoker.Invoke(argsOther);

    Assert.Throws<MockException>(
        () => fake.Verify(f => f.MyMethod(args)));
}

[Test, Isolated]
public void VerifyCallWithExplicitArguments_WhenOtherInstanceArgs_ThrowsMockException()
{
    var args = new MyArgsWithoutEquals();
    var argsOther = new MyArgsWithoutEquals();
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();

    var invoker = new Invoker(fake);
    invoker.Invoke(argsOther);

    Assert.Throws<VerifyException>(
        () => Isolate.Verify.WasCalledWithExactArguments(
            () => fake.MyMethod(args)));
}

#3

[Test]
public void VerifyCallWithExplicitArgumentsAndValues_WhenOtherInstanceArgsWithSameValues_VerifiesOk()
{
    var args = new MyArgsWithoutEquals { Id = 1 };
    var argsOther = new MyArgsWithoutEquals { Id = 1 };
    var fake = new Mock<MyClassUnderTest>();

    var invoker = new Invoker(fake.Object);
    invoker.Invoke(argsOther);

    fake.Verify(f => f.MyMethod(It.Is<MyArgsWithoutEquals>(a => a.Id == args.Id)));
}

[Test, Isolated]
public void VerifyCallWithExplicitArgumentsAndValues_WhenOtherInstanceArgsWithSameValues_VerifiesOk()
{
    var args = new MyArgsWithoutEquals { Id = 1 };
    var argsOther = new MyArgsWithoutEquals { Id = 1 };
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();

    var invoker = new Invoker(fake);
    invoker.Invoke(argsOther);

    Isolate.Verify.WasCalledWithArguments(
        () => fake.MyMethod(args)).Matching(a => ((MyArgsWithoutEquals)a[0]).Id == args.Id);
}

#4

[Test]
public void VerifyCallWithExplicitArguments_WhenOtherInstanceArgsWithEqualsImplementation_VerifiesOk()
{
    var args = new MyArgsWithEquals();
    var argsOther = new MyArgsWithEquals();
    var fake = new Mock<MyClassUnderTest>();

    var invoker = new Invoker(fake.Object);
    invoker.Invoke(argsOther);

    fake.Verify(f => f.MyMethod(args));
}

[Test, Isolated]
public void VerifyCallWithExplicitArguments_WhenOtherInstanceArgsWithEqualsImplementation_VerifiesOk()
{
    var args = new MyArgsWithEquals();
    var argsOther = new MyArgsWithEquals();
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();

    var invoker = new Invoker(fake);
    invoker.Invoke(argsOther);

    Isolate.Verify.WasCalledWithExactArguments(
        () => fake.MyMethod(args));
}

#5

[Test]
public void VerifyCallWithAnyArguments_WhenInstanceOfCorrectType_VerifiesOk()
{
    var args = new MyArgsWithoutEquals();
    var fake = new Mock<MyClassUnderTest>();

    var invoker = new Invoker(fake.Object);
    invoker.Invoke(args);

    fake.Verify(f => f.MyMethod(It.IsAny<MyArgsWithoutEquals>()));
}

[Test, Isolated]
public void VerifyCallWithAnyArguments_WhenInstanceOfCorrectType_VerifiesOk()
{
    var args = new MyArgsWithoutEquals();
    var fake = Isolate.Fake.Instance<MyClassUnderTest>();
            
    var invoker = new Invoker(fake);
    invoker.Invoke(args);

    Isolate.Verify.WasCalledWithAnyArguments(() => fake.MyMethod(null));
}

Test duration

I also spotted something else. The difference in duration of the tests. Even though this isn’t a realistic scenario, since I only have five tests, I thinkt it’s kind of fun to see. It would be interesting to swap in a real scenario where there’s alot of faking going on.
Moq vs Typemock - Test duration

When doing these tests I was consuming:

  • Moq v4.0.10501.6 (what’s with all these decimals. I just wan’t to be able to determine older/never)
  • Typemock v6.0.3.0

I also tested to disable Typemock and to run the Moq test alone. The result was the same.

Download the code here

The conclusions

Conclusion #1
Regarding to the It.IsAny and It.Is(validation expression), the conclusion is that the only API member I’m missing, is the It.IsAny. Why? Because I really don’t like the way I have to pass null to WithAnyArguments, in Typemock. I really hope they implement something similar. And if they have, please correct me.

Conclusion #2
I also would like Typemock to provide me a solution where I don’t have to verify against an object[] as in code example #3 above.

Conclusion #3
I like the way Typemock uses “Fakes” instead of “Mocks”. This since Fakes covers both Stubs and Mocks, while the Moq framework lets Mock represent both Stubs and Mocks, which is somewhat confusing.

So, so far I’m happy with the invested money in Typemock.

//Daniel

Tagged ,

Typemock – Beautiful exceptions

So I recently started to use Typemock instead of Moq and I’m currently getting acquainted with the API. I just found something that I really think shows that they are putting in some effort to the product. It’s no fancy feature just something that I think every Mocking-framework should provide: “Informative and guiding exceptions when you use the framework inappropriately.”

Take this for an example:

[Test, Isolated]
public void Execute_WhenNoNotationExistsAndDateIsToday_RegistrationIsAllowed()
{
    var scenario = new RegisterSleepNotationScenario().ConfigureParams(
        p => p.NewSleepNotation = new SleepNotation(new Kid(), Week.Current, DayOfWeek.Monday, 1, 50));
    var sleepNotationsSourceFake = Isolate.Fake.Instance<IEditableObjectSource<SleepNotation>>();
    scenario.SleepNotaionsSource = sleepNotationsSourceFake;

    scenario.Execute();

    Isolate.Verify.WasCalledWithExactArguments(
        () => sleepNotationsSourceFake.Insert(scenario.Params.NewSleepNotation));
}

This test resulted in the following exception from Typemock:

This informative message then lead me to the small change:

var expectedNewSleepNotation = scenario.Params.NewSleepNotation;
Isolate.Verify.WasCalledWithExactArguments(() => sleepNotationsSourceFake.Insert(expectedNewSleepNotation));

Which resulted in a green test and a happy developer, without having to use Google or the Typemock-documentations to search for: “how to consume WasCalledWithExactArguments”. As it should be. Thank you Typemock!

//Daniel

Tagged

How-to isolate DateTime.Now in your unit tests

Updated: The code for the OverrideDateTimeWithQueue method and the test that consumed it has been updated.

I’m currently working on an application that makes some calculations depending on dates. In one scenario I wanted to ensure that a correct timeintervall is created from DateTime.Now. Since I’m not using TypeMock an easy way is to don’t access DateTime.Now directly in my code, but via instead via a static proxy, to which I can inject code that tells it what dates to return. This is not a new solution, search with Google for eg. “unit test datetime.now” and see for your self.

I also wanted the ability to Queue dates, for the ability to setup a range of expected dates that would be dequeued at each requested for DateTime.Now. One simple implementation I could think of was to let my static proxy implementation use a Func that per default just returns DateTime.Now; but of course can be overridden by the user.

Before we look at the tests, lets give some insight to the domain: With the use of a recorder I can create recordings. Each recording will get a start- and stoptime and will be created when recorder.Stop is invoked. The Recording can then be fetched/accessed via recorder.LastRecording or via an event: RecordingCompleted; raised by the recorder. The Recorder holds StartedAt and StoppedAt timestamps which are used to populate the Recording.

When I want the value of DateTime.Now in my domain, I fetch it from my proxy: DateTimeNow.Value

The Old test

[TestMethod]
public void Start_WhenSecondCall_TimeStampsAreUpdated()
{
	var recorder = RecorderFactoryForTests.Default();
	recorder.Start();
	recorder.Stop();

	DateTimeAsserts.GainsValueBetweenNow(
		() => recorder.StartedAt, recorder.Start);
	Assert.IsNull(recorder.StoppedAt);
}

DateTimeAsserts.GainsValueBetweenNow, ensures that when recorder.Start is invoked a before and after timestamp is stored away and then is the recorder.StartedAt compared against these dates. Not so good, since I can’t isolate the value.

The New test

[TestMethod]
public void Start_WhenSecondCall_TimeStampsAreUpdated()
{
    var dateTimes = new[] { 
            DateTime.Parse("2010-01-01 00:00:00"),
            DateTime.Parse("2010-01-01 00:01:00"),
            DateTime.Parse("2010-01-01 00:02:00") };
    var recorder = RecorderFactoryForTests.Default();

    TestHelper.OverrideDateTimeWithQueue(
        () =>
        {
            recorder.Start();
            recorder.Stop();
            recorder.Start();
        }, dateTimes);

    Assert.AreEqual(dateTimes[2], recorder.StartedAt);
    Assert.IsNull(recorder.StoppedAt);
}

Now, the first item in dateTimes will be consumed by recorder.Start() and assigned to recorder.StartedAt. The second element will be assigned to StoppedAt in recorder.Stop() and the last value will be assigned to recorder.StartedAt when the last recorder.Start() call is executed.

The test will of course break if let’s say the first call to recorder.Start() invokes DateTimeNow.Value two times. Another way to write the test is:

[TestMethod]
public void Start_WhenSecondCall_TimeStampsAreUpdated()
{
    var expectedStartedAt = DateTime.Parse("2010-01-01 00:02:00");
    var recorder = RecorderFactoryForTests.Default();

    recorder.Start();
    recorder.Stop();

    DateTimeNow.Set(() => expectedStartedAt);
    recorder.Start();

    Assert.AreEqual(expectedStartedAt, recorder.StartedAt);
    Assert.IsNull(recorder.StoppedAt);
}

Code for DateTimeNow

public static class DateTimeNow
{
    private static readonly object _lock;
    private static Func<DateTime> DateTimeNowFunc { get; set; }

    static DateTimeNow()
    {
        _lock = new object();
        Reset();
    }

    public static DateTime Value
    {
        get { return DateTimeNowFunc.Invoke(); }
    }

    public static void Set(Func<DateTime> dateTimeNowFunc)
    {
        lock (_lock)
        {
            DateTimeNowFunc = dateTimeNowFunc;
        }
    }

    public static void Reset()
    {
        Set(() => DateTime.Now);
    }
}

Code for the TestHelper.OverrideDateTimeWithQueue

public static void OverrideDateTimeWithQueue(Action action, params DateTime[] expectedDates)
{
    var queuedDates = new Queue<DateTime>(expectedDates);

    try
    {
        DateTimeNow.Set(queuedDates.Dequeue);
        action.Invoke();
    }
    finally
    {
        DateTimeNow.Reset();
    }
}

That’s it.

//Daniel

Tagged

Faking API for stubs and mocks

Just for fun I started to build my own API for taking care of stubbing and mocking while writing my tests. It wasn’t all for fun, since I didn’t like the API of the Moq-framework (read earlier writings about this) I thought that I could wrap Moq in my own API. Since I’m not consuming all the functionality of the Moq-framework, I will get a more slim API that doesn’t tangle stubs and mocks. It will also make it possible for me to switch (why I would like this I really don’t know) for another framework than Moq; or actually build my own instead of just a wrapper.

The result? Well as I see it it all start with the intent of faking something (use a stand-in); either as a simple stub or a mock. And the stub and mock should have different configuration API.

The result so far (since I add functionality when I need it)

var newUserAccount = UserAccountFactoryForTests.CreateValidUserAccount();
var entityStoreMock = Fake<IEntityStore>.Mock();
var componentContainerStub = Fake<IoCContainer>.Stub()
    .Returns(c => c.Resolve<IEntityStore>(), entityStoreMock.MockedObject);
var service = new SecurityService { ServicesIoCContainer = componentContainerStub.StubbedObject };

The code can be downloaded from here.

//Daniel

Tagged , , ,
Follow

Get every new post delivered to your Inbox.