Archive for the ‘MSTest’ Category
Rationalising mocked dependencies using concrete types
This really is amazingly obvious and simple, but for some reason it never occurred to me.
The situation I’ve been getting myself into is that I have Business Logic actions that do a very discrete bit of logic, these will have dependencies on data access repositories as well as other business logic actions (potentially). I was happily using interfaces for the data access dependencies and then continued to use them for business logic dependencies, this lead to a bit of a mass of interfaces, and I also ended up with tests that mocked all these dependencies, resulting in missing lots of problems that occur in the interaction between business logic actions.
What I really want is that all data access dependencies can be replaced by mocks, but the ‘real’ instances of all the business logic actions are used. This seemed hard to achieve as we are not using an IOC container for our dependency injection (What a pain!) so use a default constructor for each class that just provides real implementations. So if we use a real instance of the business logic dependency we either have to know about it’s dependencies (resulting in massive constructors for all possible dependencies in the object graph).
The solution I hit upon today seems kind of obvious now (and of course is completely irrelevant if you have an IOC Container). Specify all data access dependcies by interface so they can be mocked out. Specify all business logic dependencies as concrete dependencies (still in the constructor). Use default constructors to use default instances of all the dependencies. In tests create all business logic objects for the required object graph using dependency injection, use mocks for data access dependencies and real instances for business logic actions.
public class Class1
{
private IDataAccess1 dataAccess1Dependency;
private Class2 class2Dependency;
public Class1()
: this(new DataAccess1(), new Class2())
{ }
public Class1(IDataAccess1 dataAccess1, Class2 class2)
{
this.dataAccess1Dependency = dataAccess1;
this.class2Dependency = class2;
}
public int MethodToTest()
{
return class2Dependency.Method() + dataAccess1Dependency.GetInt();
}
}
|
public class Class2
{
private IDataAccess2 dataAccess2Dependency;
public Class2()
: this(new DataAccess2())
{ }
public Class2(IDataAccess2 dataAccess2)
{
this.dataAccess2Dependency = dataAccess2;
}
public int Method()
{
return dataAccess2Dependency.GetInt();
}
}
|
/// <summary>
///A test for MethodToTest
///</summary>
[TestMethod()]
public void MethodToTestTest()
{
MockRepository mocks = new MockRepository();
IDataAccess1 mockDA1 = mocks.DynamicMock<IDataAccess1>();
IDataAccess2 mockDA2 = mocks.DynamicMock<IDataAccess2>();
Class2 class2Instance = new Class2(mockDA2);
Class1 target = new Class1(mockDA1, class2Instance);
using (mocks.Record())
{
Expect.Call(mockDA1.GetInt()).Return(5);
Expect.Call(mockDA2.GetInt()).Return(6);
}
using (mocks.Playback())
{
int expected = 11;//5+6
int actual = target.MethodToTest();
Assert.AreEqual(expected, actual);
}
}
|
Upgrading CAB solution to Visual Studio 2008 and making all the tests pass
For one reason or another we’ve recently upgraded the Microsoft Composite Application Block solution to a Visual Studioo 2008 solution. The conversion appeared to succeed, but when we tried to run the unit tests we had lots of failures. I then went through trying to figure out whether these failures represented functional failings in the CAB built from this source (this would be a ‘bad thing’) Or whether they were issues with the tests.
This post details the steps required to fix all the unit tests
Expected Exception Attribute not working
The first problem seemed to be that any test that had an ExpectedException attribute failed, with the reason being that an exception was thrown… hang on… isn’t this what we wanted? Seems that the attribute wasn’t being recognised by the unit test framework (MSTest). The cause being that the test projects had a reference to the wrong version of the MSTest dll. So although Visual Studio was using MSTest 2008 to run the tests it was looking for attribute definitions in another version of the dll… Seems like this should have been picked up by the conversion wizard. Anyhow, it’s a simple fix, remove all the references to Microsoft.VisualStudio.QualityTools.UnitTestFramework and add them again making sure you get the V9.0 dlls.
AppDomain Base Directory has changed
The next issue I resolved was a little more tricky. Several tests were failing in the FileStatePersistenceService, and after some digging it looked like it was because there were lots of relative addresses being used for generating files, the files were therefore being created in the AppDomain.CurrentDomain.BaseDirectory, but then being looked for in the Environment.CurrentDirectory. In MSTest 2005 these happened to be the same location. Due to a change in MSTest 2008 they are no longer the same. This page explained the problem and a fix, which simply involves adding a line to run before the test that changes the BaseDirectory.
AppDomain.CurrentDomain.SetData(“APPBASE”, Environment.CurrentDirectory);
Namespace changes on embedded resources
The next issue was one found in ReflectionModuleEnumeratorFixture and ModuleLoaderServiceFixture. Both of these test fixtures involved dynamically compiling classes from embedded resources. (I can’t help but wonder if this is overkill for a unit test). Anyway, this was kind of hard to diagnose, the only problem being that a stream was being created from the ExecutingAssembly().GetManifestResourceStream(input), and this was returning null. After debugging and looking at what was returned from GetManifestResourceNames() I noticed that there was a mismatch in the names being looked for and those used for the embedded resources. To fix the tests I changed all the calls to compile files in the constructor to reference the correct names. This involved replacing Microsoft.Practices.CompositeUI.Tests.Mocks.Src with Microsoft.Practices.CompositeUI.Tests.Instrumentation.Mocks.Src
Last Test – LoadModuleReferencingMissingAssembly
The final test to outsmart me was the LoadModuleReferencingMissingAssembly test, this test attempts to load a module that calls out to another module that has not been included in the ModuleInfo. An exception should be thrown when the call is made to Module.load(). However in 2008 no such exception is thrown, with execution proceeding as normal. In 2005 a FileNotFound exception is thrown saying that it can’t find the referencedAssembly. In both cases the dll is present in the output directory. At the time of writing I have been unable to fix this test, I wonder if the issue is related to the AppDomain changes, but the proposed fix doesn’t seem to work.
Any suggestions more than welcome!
Leave a Comment
Leave a Comment