So the call would be:
var result=repository.GetAssociate(new UserName(DependencyContainer.GetAssociate()));
Which you can't call from the persistence layer because
- The Dependency container is defined in an assembly not referenced by the persistence layer
- The UserName constructor is internal to the domain assembly
You could of course messy up your code by using dependency injection on everything that needs testing. This concern does partly fall down if you centralize the coupling between your domain and external dependencies, but remains when you try to test individual methods inside a class, or anything internal, private, or that accesses static methods(most testing frameworks can not handle mocking out static methods, constructors, or factories, as I understand it TypeMock can)
You could make your code messier and more prone to issues in dependent code by changing username to a public interface and changing the persistence layer to accept that interface, but then automatic business logic enforcement goes out the window. If an object outside of the domain assembly can not create a copy of a domain object it has no reason to create, then it's tougher to accidentally not pass things through the proper domain classes/methods.
So how do I test this method?
Enter TypeMock.
I have the following code in the persistence assembly's test project which does not compile:
[TestMethod]
public void GetAssociate_InvalidUser_IsNull()
{
var repository = new AssociateRepository();
var result=repository.GetAssociate(new UserName("badUser"));
Assert.IsNull(result);
}
{
var repository = new AssociateRepository();
var result=repository.GetAssociate(new UserName("badUser"));
Assert.IsNull(result);
}
Notice I said the persistence assembly, which makes the possibility of
[IInternalsVisibleTo] a poor choice.
I delete the `new UserName("badUser")` call and TypeMock springs up with a tooltip that says Alt+/ to Fake UserName.
Which immediately produces the following:
[Isolated]
[TestMethod]
public void GetAssociate_InvalidUser_IsNull()
{
UserName fakeUserName = Isolate.Fake.Instance<UserName>();
var repository = new AssociateRepository();
var result=repository.GetAssociate(fakeUserName);
Assert.IsNull(result);
}
[TestMethod]
public void GetAssociate_InvalidUser_IsNull()
{
UserName fakeUserName = Isolate.Fake.Instance<UserName>();
var repository = new AssociateRepository();
var result=repository.GetAssociate(fakeUserName);
Assert.IsNull(result);
}
and my cursor is sitting at the fakeUserName parameter with a new tooltip Set Object Behavior Alt+/
I hit that keysequence and it reflectively I assume shows me options for what this object could do, and what methods I might want to produce a value for. Since this is my first time, I don't know if it's automatically pulling in only the methods that the method I'm testing will make use of. I had only the method I wanted to fake in a drop down menu, going into that produced 3 options: Ignore Call, Return Value, Throw Exception. I enter return value and this is produced:
[Isolated]
[TestMethod]
public void GetAssociate_InvalidUser_IsNull()
{
UserName fakeUserName = Isolate.Fake.Instance<UserName>();
var repository = new AssociateRepository();
Isolate.WhenCalled(() => fakeUserName.ToString()).WillReturn();
var result=repository.GetAssociate(fakeUserName);
Assert.IsNull(result);
}
[TestMethod]
public void GetAssociate_InvalidUser_IsNull()
{
UserName fakeUserName = Isolate.Fake.Instance<UserName>();
var repository = new AssociateRepository();
Isolate.WhenCalled(() => fakeUserName.ToString()).WillReturn();
var result=repository.GetAssociate(fakeUserName);
Assert.IsNull(result);
}
My cursor is already sitting in the WillReturn waiting for me to type in the parameter. I type in "badUser", run the test, and it passes. that's terrific.
I did not have to alter my code to fit the tests. I did not have to think about testability when writing the code. I did not need any special assembly attributes. I want TypeMock. It makes life so much better.
"This is so exciting I am getting emotional. This is exactly the vision we had in mind to lower the barrier for people who want to unit test with our tools.
ReplyDeleteGreat job, team!"
By Doron Peretz - Development Manager @ Typemock