Roadblock to Mocking Unit Tests

Posted Tuesday, July 15, 2008 11:58 AM by cromwellryan

I've been a faithful unit tester for a few years now.  I may not do everything by the book (I think end-to-end unit tests are helpful), but I do get good coverage most of the time.  That said, I've found myself unable to use any of the Mock frameworks out there, because I don't use your typical Dependency Injection pattern.  That is, I don't like "building up" very freaking instance with all the "Provider" or "Service" interfaces I'm might need in the possible life of a business object.  Yes, if your Customer class is only going to create or save an Order, it feels OK, but my objects are busy dude, so I'd need the longest constructor of all time.

I prefer Dependency Resolution.  I don't use any fancy framework, I just use a good old, DI.Resolve<IBusyBee>() and go about my business.  It works wonderfully, it's light-weight (cause I don't use configuration based DI frameworks), and it's my baby.

That said, it's also been the roadblock to my mocking foray.  That was, until I "got it" today.  Long story short, here's how I roll:

Create a Mock DI Container...

Mock<IDIContainer> mockContainer = new Mock<IDIContainer>();

Create the Injected Mock instances...

Mock<INotificationManager> mockNotifMgr = newMock<INotificationManager>();
Mock<IRepository> mockRepository = newMock<IRepository>();

Tell the mock IDIContainer to return the mock instances when asked...

mockContainer.Expect(c => c.Resolve<INotificationManager>(null)).Returns(mockNotifMgr.Object);
mockContainer.Expect(c => c.Resolve<IRepository>(null)).Returns(mockRepository.Object);

Mock your heart out...

mockNotifMgr.Expect(mgr => mgr.NotifyEmailConfirmation(It.IsAny<Member>())).AtMostOnce();
Member.Register("username", "firstname", "lastname", "ryan@myus.com");

mockContainer.VerifyAll();
mockNotifMgr.VerifyAll();

I'm very happy to have finally jumped on the Moq bandwagon as it will certainly make some unit tests much easier to write.  Maybe I'll even do the test first part more faithfully now. 

FYI, I use my own DI framework which is just a glorified HashTable.  It works for me and it is quick.  Moq has also become my Mock framework of choice for no good reason other than I downloaded it first.

Filed under:

Comments

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 10:30 AM by Ben Scheirman

Why mock your container?

If you want to use your container for hydrating an object, that's fine... but no need to mock it.

You can just stuff whatever mocks/stubs you want in the container.

Also, I'm wondering why you don't like constructor injection.  One of the whole reasons for DI is the Dependency Inversion Principle.  Rather than your code depending on lots of external classes, you instead accept their interfaces as ctor paramters.  I think this is more appropriate than having all of your classes use your DI service locator.  That's a coupling that doesn't make a whole lot of sense.

And now that you have all of your code coupled to your service locator, what if you wanted to move to a more mature, flexible container?  Windsor for example has lots of features you might not know you need until later.  (I say this because I, too, created my own IoC container and I wish I hadn't.)

You might also look at AutoMockingContainer for some extra inspiration magic -- just beware that it can hide potential dependency smells in your code.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 10:44 AM by cromwellryan

It's important in this scenerio, because I need to set the expectations of that Mock<T> instance and that instance is what needs to be used.  That is, the mockRepository instance that I set the Expectation upon, also needs to be the instance used to call SaveOrUpdate.  Maybe that is an incorrect assumption regarding the Mock<T> implementation, but I had assumed each instance of Mock<T> recorded it's own Expecactations and thus that instance needs to be the one resolved.

I personally don't see any benefit to the use of Constructor injection.  You have still coupled to the same extent: my consumer still requires an INotificationManager regardless from where it originates.

In fact, I believe this makes my Domain Model more usable in that I don't have to use my DI framework to instanciate every injected object.

For instance, I can call Customer c = new Customer( "Jon", "Doe" ) rather than Customer.Create("Jon", "Doe").  This, though, is simply my current understanding of the usage patterns associated with frameworks like Windsor and Spring.

Does this jive with your understanding?

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 10:51 AM by Aaron Jensen

Hi Ryan,

Mocking, IoC, and unit testing are all great patterns. It's always good to see other bloggers bloging about them. Perusing around your blog it looks like you've got some other good information in here as well.

I wanted to point out a few areas in your post that I don't agree with just so that your readers can see another point of view. I'm not trying to insult or berate you, I'd just like to share my thoughts.

First you refer to "end-to-end" unit tests being helpful. I totally agree, however I tend to call them integration tests. Semantic difference, but helps in communication. It also means that you're allowed to both Unit test and Integration test and still be doing things by the book.

Next you mention that your "objects are busy" and you'd "need the biggest constructor of all time". I think that what you're seeing here is actually a code smell. Your objects may be violating the Single Responsibility Principle (en.wikipedia.org/.../Single_responsibility_principle) or you may be missing some abstractions that would allow you to combine multiple dependencies into some form of aggregate.

Generally speaking, if you have more than 2-4 dependencies on an object, that object is probably doing too much orchestration.

What you call Dependency Resolution vs Dependency Injection is quite minor. I feel it worth mentioning that often times there is very little configuration for Dependency Injection containers and if that is your only qualm with them I'd recommend looking into them again. The issue you felt with mocking and that pattern is also a smell in my opinion. Making an object aware of the container should be a last resort. It is much easier just to pass the objects (whether they be real or mocks) into a constructor.

The next thing that caught my eye was the use of VerifyAll on the Container. Are you really testing that the container was called in this test? Does it matter? If it does, shouldn't it be a separate test? Though it doesn't look like it, VerifyAll is an assert. You are asserting that your system under test invoked a method. Generally you should try and assert one thing per test so that when things break you know what broke. The use of VerifyAll violates this.

Is Member.Register a static method? If so, it seems like your Dependency Resolution may have come about in part to another issue... that is using static methods to do complex things. The nice thing about DI Containers is that you can set lifetimes of objects, so you can have a Singleton object whose lifetime is managed by the container rather than a GetInstance method or, worse yet, a static class. Those objects are also easier to test because their dependencies can also be injected.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 10:55 AM by Aaron Jensen

"For instance, I can call Customer c = new Customer( "Jon", "Doe" ) rather than Customer.Create("Jon", "Doe").  This, though, is simply my current understanding of the usage patterns associated with frameworks like Windsor and Spring."

It sounds like your domain entities are relying on services which is also generally considered an anti-pattern. Domain objects should rely purely on domain objects to do their job.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 11:13 AM by John Teague

I think what Ben is saying (he'll correct me if I'm wrong :-) is that you traded one tight coupling for another.  You're now coupled to your DI.  Does it have object lifecycle management? Do you really want to add that complexity to yours when you get it for free with other IOC containers?

What constructor injection gives you is removes your dependency on a specific implementation of your interface.  With Constructor Injection your NotificationManager can be changed for your testing or if you need to change it later.

Also, if your objects are indeed "busy" then you may want to consider if you're violating Single Responsibility Principle / Separation of Concerns.  It could be that your behavior should be broken up into smaller classes who have their own dependencies.

Single Responsibility Principle states that an object "should have one reason to change."  Having a lot of dependencies in a class is my first smell that I'm voilating this principle and I need to break up functionality.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 11:22 AM by cromwellryan

Ben,

A quick scan of the Windsor documentation "Wiring with constructors and properties" (www.castleproject.org/.../wiring.html) shows that Windsor supports Public Getter/Setters for passing dependencies.  I didn't realize that, but I don't know if that is any better.

Aaron (and now John),

Semantics... You are correct, I should be more clear.  I should say, I find the tools for Unit Testing helpful in running Integration Tests.

VerifyAll on the container... Oversight during copy paste.  I would not and don't include that assertion throughout.  There are unit tests specifically around my concrete container implementation, all one of them.

Single Responsibility... I would say that the API used throughout my application(s) do diverge from the Domain object purist vision.  I could easily see someone saying that my Customer object does too much orchestration, but I would vehemently argue that it does not leave the bounds of OO.  Do I use a CustomerRepository to get a customer, yes, inside my Customer.GetById static method.  I find it makes my API compact and navigable.

To the same point, Member.Register is a static method.  It isn't fully necessary for that to even exist and I could use DependencyInjection as it, internally, resolves an IRegistrationManager instance to do it's bidding.  Member.Register is simply their for ease of use by the developer.

Can I ask how you would recommend implementing the Register (my create) method or scenerio?  For the sake of the discussion, say Register simply Creates a member instances, sends them an email thanking them, and saves that instance to the Repository backing.

Can I also ask how you feel the SRP applies to a BLL or Controller?

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 11:58 AM by Aaron Jensen

Ryan,

Regarding property injection (getters/setters) I'd recommend steering away from that too. They are typically used for optional dependencies. An object should be able to function after its constructed.

And yes, unit testing tools (Nunit, mocking, whatever) are very useful for integration tests. They should be called testing tools rather than unit testing tools, but too late to change that :)

Glad to hear about the VerifyAll thing... it's currently one of my biggest annoyances with Mock frameworks--the poor guidance on mock vs. stub.

Static methods greatly increase coupling. You mention that they are there for "ease of use by the developer". The unforutnate bit about that is by making it that easy you are likely to end up with a web of class dependencies and you can quickly get to an unmanageable mess. When your dependencies are explicit and few your code is even more navigable.

SRP on the BLL can be a bit awkward, you basically say that the responsibility is to act like a Whatever entity. If in your business domain entities have multiple responsibilites you either need to accept that or separate those entities into role based entities. You'd especially do this if you have a bounded context between the roles or they're separate domains.

SRP on the Controller is simple. Its responsibility is to delegate an action to the appropriate application service and do any adapting it needs to do to the parameters.

About implementing Register, I'd probably just delegate to a factory to do the creation, save the user in the repository, and then delegate to an email sender to thank them. You could also fire a user registered message that an email sender would listen to and send the thank you email. That sort of architecture is very nice and its something we're trying to move to.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 12:10 PM by cromwellryan

I like your definition of the SRP on the Controller.  I think it is missing in most examples of Controllers and should be conveyed more prominently.

I'll have to give your Register example a run and see how things pan out.  I'm not sure I see the increased coupling caused by static methods, but I will keep my eyes open as I attemp to understand and incorporate DDD into my repertoire.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 12:29 PM by Aaron Jensen

It's not that it will cause increased coupling directly, but it enables developers to easily increase coupling. They don't need an instance, they just call a static method. This makes testing more convoluted and creates real dependencies that don't look like the other dependencies. That's a bad thing.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 12:38 PM by cromwellryan

I see what you are getting at.  The consumer of the Member.Register class has no real chance of easily Mocking the functionality provided by Register and is essentially forced to create a hard dependency, unless they create some wrapper.

I hadn't really  taken that into account.

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 12:42 PM by hammett

> For instance, I can call Customer c =

> new Customer( "Jon", "Doe" ) rather than

> Customer.Create("Jon", "Doe").

Spring, windsor, whatever other ioc container shouldn't be used to create classes that represent the domain/state, they should only be concerned with providing services...

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 12:49 PM by cromwellryan

hammett,

With Aarons series of comments walking me through these topics, I believe this is clearing up and I definitely take your point.  

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 12:59 PM by Jeff Tucker

Here's a good post on the google test blog about "static cling" which I think would be helpful.  I've found this solution to be highly useful in refactoring existing static cling.  Example is in java but should be readily applicable in .Net

# re: Roadblock to Mocking Unit Tests

Tuesday, July 15, 2008 1:04 PM by cromwellryan

Jeff,

Believe I found the article (googletesting.blogspot.com/.../defeat-static-cling.html) you were referring to.  That is a great article.  Wish I would have seen that a while ago.  Thanks.

Leave a Comment

(required) 
(required) 
(optional)
(required)