Why do we need SystemWrapper?
TDD example with Rhino Mocks and SystemWrapper.
Goal:
Requirements:
1. Create new Class Library project and name it MockTutorial.
2. Rename Class1 to DirectoryInfoSample so your code looks like this:
1: namespace MockTutorial
2: {
3: public class DirectoryInfoSample
4: {
5: }
6: }
1: public class DirectoryInfoSampleTests
2: {
3: }
4. We need to add references to our unit test framework, Rhino Mocks, and SystemWrapper libraries.
5. Create our first test. Remember that our method should try to create directory and there two possible cases (directory doesn’t exist and directory exists). It means that we’ll need two separate tests. Let’s create the first test when directory already exists.The signature for our method under test will be public bool TryToCreateDirectory(IDirectoryInfoWrap directory)You also will need to add using statements for your unit testing framework, Rhino Mocks, and SystemWrapper:
1: using SystemWrapper.IO;
2: using MbUnit.Framework;
3: using Rhino.Mocks;
Here comes the test.
1: [Test]
2: public void When_try_to_create_directory_that_already_exists_return_false()
3: {
4: var directoryInfoStub = MockRepository.GenerateStub<IDirectoryInfoWrap>();
5: directoryInfoStub.Stub(x => x.Exists).Return(true);
6: Assert.AreEqual(false, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoStub));
7: }
6. If you try to compile, it’s going to fail because we didn’t create TryToCreateDirectory method.
Let’s create the method that is going to satisfy our test.
1: public bool TryToCreateDirectory(IDirectoryInfoWrap directory)
2: {
3: return false;
4: }
7. Next we want to create our second test that expects that directory doesn’t exists and creates it.
1: [Test]
2: public void When_try_to_create_directory_that_does_not_exist_return_true()
3: {
4: var directoryInfoStub = MockRepository.GenerateStub<IDirectoryInfoWrap>();
5: directoryInfoStub.Stub(x => x.Exists).Return(false);
6: Assert.AreEqual(true, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoStub));
7: }
If you try to run the test, it will fail because in our test we expect TryToCreateDirectory method to return true.
8. It’s time again to work on our method under test.
1: public bool TryToCreateDirectory(IDirectoryInfoWrap directory)
2: {
3: if (directory.Exists)
4: return false;
5:
6: return true;
7: }
Now our tests should pass. Wait, but how do we know if the directory was created?
1: [Test]
2: public void When_try_to_create_directory_that_does_not_exist_return_true()
3: {
4: var directoryInfoMock = MockRepository.GenerateMock<IDirectoryInfoWrap>();
5: directoryInfoMock.Stub(x => x.Exists).Return(false);
6: directoryInfoMock.Expect(x => x.Create());
7: Assert.AreEqual(true, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoMock));
8:
9: directoryInfoMock.VerifyAllExpectations();
10: }
It will work but I prefer to use stubs and call new method in Rhino Mocks AssertWasCalled. Isn’t it looks cleaner?
1: [Test]
2: public void When_try_to_create_directory_that_does_not_exist_return_true()
3: {
4: var directoryInfoStub = MockRepository.GenerateStub<IDirectoryInfoWrap>();
5: directoryInfoStub.Stub(x => x.Exists).Return(false);
6: Assert.AreEqual(true, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoStub));
7:
8: directoryInfoStub.AssertWasCalled(x => x.Create());
9: }
10. Call Create() in our TryToCreateDirectory method.
1: public bool TryToCreateDirectory(IDirectoryInfoWrap directory)
2: {
3: if (directory.Exists)
4: return false;
5:
6: directory.Create();
7: return true;
8: }
In this case we call Rhino Mocks method AssertWasNotCalled.
1: [Test]
2: public void When_try_to_create_directory_that_already_exists_return_false()
3: {
4: var directoryInfoStub = MockRepository.GenerateStub<IDirectoryInfoWrap>();
5: directoryInfoStub.Stub(x => x.Exists).Return(true);
6: Assert.AreEqual(false, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoStub));
7:
8: directoryInfoStub.AssertWasNotCalled(x => x.Create());
9: }
Great tutorial.. Well structured and easy to understand, while still giving a solid coverage of the fundamentals..
Damian, thanks
Great tutorial, I have come across this issue many times and SystemWrapper nicely solves it.
I have added a few more classes for System.IO – see the patch on codeplex.
Using the Funq DI container, it is also possible to wrap classes which require parameters to the constructor (MemoryStream etc.).
Iain,
Thanks a lot for submitting a patch. I added you as a developer on the project so feel free to commit any changes.
Very informational and clear. Hope to see more.
rgds
Sunit
Vadim:
Great tutorial. Could you send me the .Net 2.0 example code?
Thanks,
Adrian
Andrian,
You can get sample code from http://systemwrapper.codeplex.com/SourceControl/ListDownloadableCommits.aspx. All samples in .Net 3.5. In .Net 2.0 on of the example is going to look something like this:
[Test]
public void When_try_to_create_directory_that_does_not_exist_return_true_dot_NET_2()
{
IDirectoryInfoWrap directoryInfoStub =
MockRepository.GenerateStub();
RhinoMocksExtensions.Stub(directoryInfoStub,
delegate(IDirectoryInfoWrap dirInfo)
{
bool b = dirInfo.Exists;
}).Return(false);
Assert.AreEqual(true, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoStub));
RhinoMocksExtensions.AssertWasCalled(directoryInfoStub,
delegate(IDirectoryInfoWrap dirInfo)
{
dirInfo.Create();
});
}