CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeffrey Palermo (.com)

Blog moved to www.jeffreypalermo.com

Objects have dependencies. Methods don't

For more counter-intuitive banter, subscribe to my feed:  http://feeds.feedburner.com/jeffreypalermo

There is quite a bit of talk lately about unit testing using the extract method and override, or "inherit & override" method for stubbing out a method for unit testing.  Methods don't have dependencies, and methods aren't dependencies.

Objects are dependencies, and object have dependencies.  One object will depend on another object.  Objects are cohesive and present a contract of behavior so other objects know what behavior they can reliably leverage.  Because an object is cohesive, everything necessary to perform all its behavior can be passed into the object's constructor at the beginning of the object's life.  Then, that object can perform all of the operations.


In order to test a particular object, I might have to pass some fake objects (stubs, mocks, etc) into the constructor, but the object under test doesn't care as long as the type is satisfied.  If I can't test an object by passing in fakes to the constructor (and I can compromise sometimes by using setter injection), then the object is less than cohesive, and I should search the design of the object for an extra concern that is trying to get out.  Once I find the extra concern, I would separate the concern (separation of concerns) into its own object and have than as an explicit dependency by requiring it be passed into the constructor (dependency injection).

Michael Feathers outlines this extract method and override testing technique in his book, "Working Effectively with Legacy Code", and I've used the technique many times to break nasty dependencies on legacy code in order to get it under test.  This is necessary because legacy code can't be safely refactored until it has a safety net of test coverage.

If your unit test has to know that another method on the same object is being called, then the unit test knows too much about the implementation of the object.  The unit test should be doing black box testing on the object under test.  In other words, the unit test shouldn't care about what code is written or if 1 method or 10,000 methods inside the object are actually called.  The unit test merely sets up explicit object dependencies and test state, interaction or both.


Published Mar 11 2008, 06:04 PM by Jeffrey Palermo
Filed under:

Comments

robkitson said:

Quick question... if you're using a mock object framework and you are setting up your expectations in your tests, don't your tests know a lot about the implementation?

# March 11, 2008 8:02 PM

Jimmy Bogard said:

This would lead me to think that MVC controllers should be POCOs, infrastructure ignorant.

# March 11, 2008 8:40 PM

Jeffrey Palermo said:

@Weex,

In a  good unit test, I ought to be able to rewrite class code in many ways as long as to the caller it has the same observable behavior.  That's black box.  Only observable behavior is tested.  Inside the class, I shouldn't have to mess with what methods an object calls on itself.

You are correct in saying that you should not couple tests with the object implementation, only observable behavior.  In other words, black box.  Now, the black box is VERY small.  Just an object.

# March 11, 2008 9:29 PM

Jeffrey Palermo said:

@robkitson,

My remarks don't affect whether you are using a mock framework or not.

The tests should set up expectations on the observable behavior.  Observable from the outside.  After the test is failing because the production code isn't there yet, you can write whatever code satisfies the test.  You will obviously know about the implementation, but your unit test should know.  The unit test should only be concerned with observable behavior.

# March 11, 2008 9:31 PM

Jeffrey Palermo said:

@Jimmy,

I think a lot of classes should be infrastructure ignorant, but I don't think MVC controllers will be, at least not if you are leveraging an infrastructure base class like Controller or SmartDispatchController in Monorail.  The testing method shouldn't change based on what infrastructure you use.  The infrastructure should not stand in the way of clean testability.

# March 11, 2008 9:32 PM

hammett said:

Can you show a code snippet of what, in your opinion, is a clean controller test?

# March 11, 2008 11:27 PM

Jeffrey Palermo said:

@hammett,

Not on this comment thread because MVC frameworks are orthogonal to this post.  I recently posted a controller test for ASP.NET MVC, and I certainly defer to you regarding the Monorail testing given that I've only completed 1 Monorail project and am very ignorant of all the capabilities of the SmartDispatchController class.

# March 11, 2008 11:33 PM

Tom said:

I'll bite...

"Methods don't have dependencies, and methods aren't dependencies.  Objects are dependencies, and object have dependencies."

If object X has a dependency on object Y, what constitutes this dependency?  Is it not the method calls that object X makes on object Y?  Objects don't have dependencies -- TYPES have dependencies and they're expressed through methods.

"Objects are cohesive and present a contract of behavior so other objects know what behavior they can reliably leverage."

Objects most certainly do NOT present a contract of behavior -- types do.  Moreover, behavior is expressed through methods, not objects.

"Because an object is cohesive, everything necessary to perform all its behavior can be passed into the object's constructor at the beginning of the object's life.  Then, that object can perform all of the operations"

This line of thought seems to make method parameters sort of unnecessary, no?

"In order to test a particular object, I might have to pass some fake objects (stubs, mocks, etc) into the constructor, but the object under test doesn't care as long as the type is satisfied."

Exactly my point -- a contract is expressed through TYPES not objects.

"If I can't test an object by passing in fakes to the constructor (and I can compromise sometimes by using setter injection), then the object is less than cohesive, and I should search the design of the object for an extra concern that is trying to get out.  Once I find the extra concern, I would separate the concern (separation of concerns) into its own object and have than as an explicit dependency by requiring it be passed into the constructor (dependency injection)."

No. You would separate the concern into its own TYPE.  And most likely, you'd express that type's contract through an interface so that you could mock it out for your tests.

"Michael Feathers outlines this extract method and override testing technique in his book..."

Not really sure what any of the above has to do with the extract method and override refactoring?  You were just talking about dependency injection, which is basically a polar opposite of extract and override (with dependency injection, you pass the dependency in, whereas with override and refactor the type itself is responsible for creating an instance of the dependency).

"The unit test should be doing black box testing on the object under test..."

Ditto what Weex said.

# March 11, 2008 11:55 PM

Jeffrey Palermo said:

Tom,

In C#, Java, yes, "Type" is more correct here.  I was trying to be general because I think this applies to other OO languages as well.  Some other OO languages are not statically typed.

# March 12, 2008 7:14 AM

Dew Drop - March 12, 2008 | Alvin Ashcraft's Morning Dew said:

Pingback from  Dew Drop - March 12, 2008 | Alvin Ashcraft's Morning Dew

# March 12, 2008 9:06 AM

Jeff Tucker said:

I agree with you in principle and from a testing perspective, but what about a situation like Strategy?  In strategy, I would (usually) invoke the strategy through a method, and typically this is only one method on my object.  I may still inject the strategy interface through the constructor, but it's still a dependency of the method itself as the rest of the object will function correctly without it.  I can test that the strategy is called by using a mock and I probably won't use a mock to test the strategy itself (which I will test separately).  However, I still see this as being a dependency on a method in many cases (although I can think of several exceptions).  Your thoughts?  Also, could methods be dependencies in the case of delegates?  I think that the same argument could be made here.

# March 12, 2008 2:51 PM

Greg said:

weex hit it on the head but ...

methods don't have dependencies? functional code I think changes this...

Somebody has already mentioned the Strategy pattern but the first one that came to my mind was specification ...

object.Validate(IEnumerable<Specification<whatever>>)

# March 13, 2008 12:18 AM

Reflective Perspective - Chris Alcock » The Morning Brew #52 said:

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #52

# March 13, 2008 4:08 AM

Jeffrey Palermo said:

Clarifying.  Yes,  method can have dependencies, and these are exposed via method arguments.  If a method needs an object in order to function properly, that object should be passed in to a method if it is not  a member of the class.

# March 13, 2008 9:38 AM

Tom said:

"If a method needs an object in order to function properly, that object should be passed in to a method if it is not  a member of the class."

Now there's a revelation!

# March 13, 2008 2:36 PM

Colin Jack said:

"If I can't test an object by passing in fakes to the constructor (and I can compromise sometimes by using setter injection), then the object is less than cohesive"

Not sure I understand this, I think you are saying that a class is not cohesive if all its dependencies are not injected?

# March 18, 2008 6:42 AM

About Jeffrey Palermo

Jeffrey Palermo is a software management consultant and the CTO of Headspring Systems in Austin, TX. Jeffrey specializes in Agile coaching and helps companies double the productivity of software teams. Jeffrey is an MCSD.Net , Microsoft MVP, Certified Scrummaster, Austin .Net User Group leader, AgileAustin board member, INETA speaker, INETA Membership Mentor, Christian, husband, father, motorcyclist, Eagle Scout, U.S. Army Veteran, and Texas A&M University graduate. Check out Devlicio.us!

This Blog

Syndication

News

Headspring Systems

View Jeffrey Palermo's profile on LinkedIn

See my new blog at .jeffreypalermo.com