A fake is a generic term that can be used to describe either a stub or a mock object (handwritten or otherwise), because they both look like the real object. Whether a fake is a stub or a mock depends how it's used in the current test. If it's used to check an interaction(asserted against), it's a mock object. Otherwise, it is a stub.
Monday, June 29, 2009
What is mock
A mock object is a fake object in the system that decides whether the unit test has passed or failed. It does so by verifying whether the object under test interacted as expected with the fake object.
Refactory to break dependency
- Extract an interface to allow replacing underlying implementation
- Inject stub implementation into a class under test
- Receiving an interface at the constructor level.
If your code under test requires more than one stub to work correctly without dependencies, adding more and more constructors ( or more and more constructor parameters) becomes a hassle, and it can even make the code less readable and less maintainable. One possible solution is using inversion of control containers. You can think of IoC containers as "smart factories" for you objects. A container provide special factory methods that take in the type of object you'd like to create and any dependencies that it needs, and then initialize the object using special configurable rules such as what constructor to call, what properties to set in what order, and so on. They are powerful when put to use on a complicated composite object hierarchy where creating an object requires creating and initializing object serveral levles down the line. Using constructor arguments to initialize objects can make you testing code more cumbersome unless you're using helper frameworks such as IoC containers for object creation. Every tie you add another dependency to the class under test, you have to create a new constructor that takes all other arguments plus a new one, make sure it calls the other constructors correctly, and make sure other users of this class initialize with the new constructor.
On the other hand, using parameters in constructors is a great way to signify to the user of your API that these parameters are non-optional. They have to be sent in when creating the object.
If you want these dependencies to be optional, use properties, which is much more relexed way to define optional dependencies adding different constructors to the class for each dependency. If you choose to use constructor injection, you'll probably also want to use IoC containers. This would be a great solution if all code in the world were using IoC, containers. The future of unit testing will use more and more of these Ioc pattern.
- Receive an interface as a property get or set.
Use this technique when you want to signify that a dependency of the class under test is optional, or if the dependency has a default instance created that doesn't create any problems during the test.
- Get a stub just before a method call
Tuesday, June 23, 2009
Test asp.net mvc route
//arrange
RouteCollection routes = new RouteCollection();
MvcApplication.RegisterRoutes(routes);
var httpContextMock = new Mock<HttpContextBase>();
httpContextMock.Expect(c => c.Request.AppRelativeCurrentExecutionFilePath).Return("~/product/list");
//act
RouteData routeData = routes.GetRouteData(httpContextMock.Object);
//assert
Assert.IsNotNull(routeData, "Should have found the route");
Assert.AreEqual("product", routeData.Value["Controller"]);
Assert.AreEqual("list", routeData.Value["action"]);
Assert.AreEqual("", routeData.Values["id"]);
Wednesday, May 27, 2009
What is a good unit test
A unit test should have the following properties:
- It should be automated and repeatable.
- It should be easy to implement.
- Once it’s written, it should remain for future use.
- Anyone should be able to run it.
- It should run at the push of a button.
- It should run quickly.
Tuesday, January 20, 2009
Create a stub with
A stub can also be created using Mocking frameworks. Semantically speaking, a stub is a simulated object, just like a mock object, that will support our test so that we can test other things. In short, a stub will always make “happy noises” when being called, and can never be used to see if the test passed or not. Calling VerifyAll() will not verify anything against stub objects. Only against mocks. Most Mocking frameworks contain the semantic notion of a stub and RhinoMocks is no exception.
[Test]
public void ReturnResultsFromStub()
{
MockRepository mocks = new MockRepository();
IGetRestuls resultGetter = mocks.Stub<IGetRestuls>();
using(repository.Record())
{
//this is still required
//to save the value for verification
resultGetter.GetSomeNumber("a");
LastCall.Return(1);
}
//verify
int result = resultGetter.GetSomeNumber("a");
//please note here we don't use mocks.VerifyAll(); because stub
// will never break tests, but if we use mocks.VerifyAll()
//will not break the test anyway.
Assert.AreEqual(1, result);
}
Strict Mork vs Non-strict mork
A strict Mock Object will only allow calling methods on it that were explicitly set via Expectations. Any call that is made which either differs by the parameter values defined, or by the method name, will usually be handled by throwing an exception while the method is being called. That means the test fails on the first unexpected method call to a strict mock object.
A Non Strict Mock will allow any call to be made to it even if it was not expected. As long as the call does not require a return value, it will, “make happy noises” and only do what’s necessary for everything in the test to work out. If a method which needs to return a value is called and we did not setup a return value as part of setting up that mock object, a RhinoMocks stub object can return the default value for that method’s return type (0 or null usually). Other frameworks may take different approaches and may throw an exception when the method is not configured to return anything.
A non strict Mock can only fail a test if an expected method was not called. You have to call the VerifyAll() method to find out if such a call is missing from the interaction or the test will pass. You can create Non Strict Mocks using RhinoMocks by calling repository.DynamicMock<type>() instead of calling repository.CreateMock<Type>().
An Example of Mock
[Test]
Public void Analyze_TooShortFileName_ErrorLoggedToService()
{
MockRepository mocks = new MockRepository();
IWebService simulatedService =
mocks.CreateMock<IWebService>();
//pre-arrange setting
using(mocks.Record())
{
simulatedService.LogError("file name was too short ");
}
//play
LogAnalyzer log = new LogAnalyzer(simulatedService);
string tooShortFileName="abc.ext";
log.Analyze(tooShortFileName);
//verify
mocks.VerifyAll();
}
The difference between mocks and stubs
Stubs can’t fail tests. Mocks can do (or they’d be called Stubs). Stubs simply replace an object so that we can test the object under test without problems. The easiest way to tell we are dealing with a Stub is to notice that the Stub can never ever fail the test. The asserts the test uses are always against the class under test. When using Mocks, on the other hand, The test will use the Mock object to verify if the test failed or not. Again, when using a Mock, the Mock object is the object that we use to see if the test failed or not.
Mock is normally used in the internal working of a void method, which has no value return.
Unit Test Best practices
-
Arrange test in your solution
It is common pratice to have a test class per tested class, a test rpoject per tested project and at lest one test method per tested method.
- Naming tests: [MethodUnderTest]_[Scenario]_[ExpectedBehavior]
- Use [Setup] and [TearDown] attributes to reuse code in your tests such as creating and initializing common objects all your tests use.
- Don’t use [Setup] and [TearDown] to initialize or destroy objects which are not shared throughout the test class in all the tests, as it makes the tests less understandable (the reader won’t know which tests use the setup method and which don’t).
Sunday, November 16, 2008
Convert to Arrange, Action, Assert
I am studying RhinoMocks, the new Arrange/Action/Assert style is more concise than the Record/Replay. Compare the style below
public void Analyze_WebServiceThrows_SendsEmail()
{
MockRepository mocks = new MockRepository();
IWebService stubService = mocks.Stub<IWebService>();
IEmailService mockEmail = mocks.CreateMock<IEmailService>();
using (mocks.Record())
{
stubService.LogError("whatever");
LastCall.Constraints(Is.Anything());
LastCall.Throw(new Exception("fake exception"));
mockEmail.SendEmail("a", "subject", "fake exception");
}
LogAnalyzer2 log = new LogAnalyzer2();
log.Service = stubService;
log.Email = mockEmail;
string tooShortFileName = "abc.ext";
log.Analyze(tooShortFileName);
mocks.VerifyAll();
}
[Test]
public void Analyze_WebServiceThrows_SendsEmail_aaa()
{
//arrange
var webServiceStub = MockRepository.GenerateStub<IWebService>();
var emailMock = MockRepository.GenerateStub<IEmailService>();
webServiceStub.Stub
(
x => x.LogError("whatever"))
.Constraints(Is.Anything())
.Throw(new Exception("fake exception")
);
//act
new LogAnalyzer2() { Email = emailMock, Service = webServiceStub }.Analyze("abc.ext");
//assert
emailMock.AssertWasCalled(x => x.SendEmail("a", "subject", "fake exception"));
}