May 2010 - Posts
In this post , i show how you can benefit from sequential mocking feature[In JustMock] for setting up expectations with successive calls of same type. To start let’s first consider the following dummy database and entity class.
- public class Person
- {
- public virtual string Name { get; set; }
- public virtual int Age { get; set; }
- }
- public interface IDataBase
- {
- T Get<T>();
- }
Now, our test goal is to return different entity for successive calls on IDataBase.Get<T>(). By default, the behavior in JustMock is override , which is similar to other popular mocking tools. By override it means that the tool will consider always the latest user setup.
Therefore, the first example will return the latest entity every-time and will fail in line #10:
- Person person1 = new Person { Age = 30, Name = "Kosev" };
- Person person2 = new Person { Age = 80, Name = "Mihail" };
- var database = Mock.Create<IDataBase>();
- Mock.Arrange(() => database.Get<Person>()).Returns(person1);
- Mock.Arrange(() => database.Get<Person>()).Returns(person2);
- //fail
- Assert.Equal(person1.GetHashCode(), database.Get<Person>().GetHashCode());
- Assert.Equal(person2.GetHashCode(), database.Get<Person>().GetHashCode());
We can solve it the following way using a Queue and that removes the item from bottom on each call:
- Person person1 = new Person { Age = 30, Name = "Kosev" };
- Person person2 = new Person { Age = 80, Name = "Mihail" };
- var database = Mock.Create<IDataBase>();
- Queue<Person> queue = new Queue<Person>();
- queue.Enqueue(person1);
- queue.Enqueue(person2);
- Mock.Arrange(() => database.Get<Person>()).Returns(queue.Dequeue());
- Assert.Equal(person1.GetHashCode(), database.Get<Person>().GetHashCode());
- Assert.Equal(person2.GetHashCode(), database.Get<Person>().GetHashCode());
This will ensure that right entity is returned but this is not an elegant solution. So, in JustMock we introduced a new option that lets you set up your expectations sequentially. Like:
- Person person1 = new Person { Age = 30, Name = "Kosev" };
- Person person2 = new Person { Age = 80, Name = "Mihail" };
- var database = Mock.Create<IDataBase>();
- Mock.Arrange(() => database.Get<Person>()).Returns(person1).InSequence();
- Mock.Arrange(() => database.Get<Person>()).Returns(person2).InSequence();
- Assert.Equal(person1.GetHashCode(), database.Get<Person>().GetHashCode());
- Assert.Equal(person2.GetHashCode(), database.Get<Person>().GetHashCode());
The “InSequence” modifier will tell the mocking tool to return the expected result as in the order it is specified by user. The solution though pretty simple but neat and way too simpler than using a collection to solve this type of cases.
Hope that helps
P.S. The example shown in my blog is using interface don’t require a profiler and you can even use a notepad and build it referencing Telerik.JustMock.dll, run it with GUI tools and it will work. But this feature also applies to concrete methods that includes JM profiler and can be implemented for more complex scenarios.
Writing state of art unit tests that can validate your every part of the framework is challenging and interesting at the same time, its like becoming a samurai. One of the key concept in this is to keep our test synced all the time as underlying code changes and thus breaking them to the furthest unit as possible. This also means, we should avoid multiple conditions embedded in a single test.
Let’s consider the following example of transfer funds.
- var currencyService = Mock.Create<ICurrencyService>();
- //// current rate
- Mock.Arrange(() => currencyService.GetConversionRate("AUS", "CAD")).Returns(0.88);
-
- Account to = new Account { Currency = "AUS", Balance = 120 };
- Account from = new Account { Currency = "CAD" };
-
- AccountService accService = new AccountService(currencyService);
-
- Assert.Throws<InvalidOperationException>(() => accService.TranferFunds(to, from, 200));
-
- accService.TranferFunds(to, from, 100);
-
- Assert.Equal(from.Balance, 88);
- Assert.Equal(20, to.Balance);
At first look, it seems ok but as you look more closely , it is actually doing two tasks in one test. At line# 10 it is trying to validate the exception for invalid fund transfer and finally it is asserting if the currency conversion is successfully made.
Here, the name of the test method itself is pretty vague. The first rule for writing unit test should always reflect to inner working of the target code, where just by looking at their names it is self explanatory. Having a obscure name for a test method not only increase the chances of cluttering the test code, but it also gives the opportunity to add multiple paths into it and eventually makes things messy as possible.
I would rater have two test methods that explicitly describes its intent and are more self-validating.
ShouldThrowExceptionForTransferringFromAccontWithNoFund
ShouldAssertTransferForExpectedConversionRate
Having, this type of breakdown also helps us pin-point reported bugs easily rather wasting any time on debugging for something more general and can minimize confusion among team members. Finally, we should always make our test F.I.R.S.T ( Fast.Independent.Repeatable.Self-Validating.Timely) [ Bob martin – Clean Code]. Only this will be enough to ensure, our test is as simple and clean as possible.
Hope that helps
--
Revisions:
Renamed ShouldThrowforInvalidFundsTransfer to a more specific as “Invalid”, “Correct/Incorrect” words are vague as well [Community].
Return type for currency should be double instead of float in case for money [Community].
In this post, i will be showing how you can mock property sets with your expected values or even action using JustMock. To begin, we have a sample interface:
- public interface IFoo
- {
- int Value { get; set; }
- }
Now, we can create a mock that will throw on any call other than the one expected, generally its a strict mock and we can do it like:
- bool expected = false;
- var foo = Mock.Create<IFoo>(BehaviorMode.Strict);
- Mock.ArrangeSet(() => { foo.Value = 1; }).DoInstead(() => expected = true);
-
- foo.Value = 1;
-
- Assert.True(expected);
Here , the method for running through our expectation for set is Mock.ArrangeSet , where we can directly set our expectations or can even set matchers into it like:
- var foo = Mock.Create<IFoo>(BehaviorMode.Strict);
-
- Mock.ArrangeSet(() => foo.Value = Arg.Matches<int>(x => x > 3));
-
- foo.Value = 4;
- foo.Value = 5;
-
- Assert.Throws<MockException>(() => foo.Value = 3);
In the example, any set for value not satisfying matcher expression will throw an MockException as this is a strict mock but what will be the case for loose mocks, where we also have to assert it. Here, let’s take an interface with an indexed property. Indexers are treated in the same way as properties. As with basic, indexers let you access your class if it were an array.
- public interface IFooIndexed
- {
- string this[int key] { get; set; }
- }
We want to setup a value for a particular index, we then will pass that mock to some implementer where it will be actually called. Once done, we want to assert that if it has been invoked properly.
- var foo = Mock.Create<IFooIndexed>();
-
- Mock.ArrangeSet(() => foo[0] = "ping");
-
- foo[0] = "ping";
-
- Mock.AssertSet(() => foo[0] = "ping");
In the above example, both the values are user defined, it might happen that we want to make it more dynamic, In this example, i arranged it up for set with any value and finally checked if it is set with the one i am looking for.
- var foo = Mock.Create<IFooIndexed>();
-
- Mock.ArrangeSet(() => foo[0] = Arg.Any<string>());
-
- foo[0] = "ping";
-
- Mock.AssertSet(() => foo[0] = Arg.Matches<string>(x => string.Compare("ping", x) == 0));
This is more or less of mocking user sets , but we can further have it to throw exception or even do our own task for a particular set , like :
- Mock.ArrangeSet(() => foo.MyProperty = 10).Throws(new ArgumentException());
Or
- bool expected = false;
- var foo = Mock.Create<IFoo>(BehaviorMode.Strict);
- Mock.ArrangeSet(() => { foo.Value = 1; }).DoInstead(() => expected = true);
-
- foo.Value = 1;
-
- Assert.True(expected);
Or call the original setter , in this example it will throw an NotImplementedExpectation
- var foo = Mock.Create<FooAbstract>(BehaviorMode.Strict);
- Mock.ArrangeSet(() => { foo.Value = 1; }).CallOriginal();
- Assert.Throws<NotImplementedException>(() => { foo.Value = 1; });
Finally, try all these, find issues, post them to forum and make it work for you :-).
Hope that helps,
More Posts