Jeffrey Palermo (.com)

Sponsors

The Lounge

Wicked Cool Jobs

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.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.


Posted Tue, Mar 11 2008 6:04 PM by Jeffrey Palermo
Filed under:

[Advertisement]

Comments

Weex wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 8:02 PM

The unit test should be doing black box testing on the object under test. - That's something new :) You should not couple tests with implementation, is that what you wanted to say? To test method's contact, not it's implementation.

robkitson wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 8:02 PM

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?

Jimmy Bogard wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 8:40 PM

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

Jeffrey Palermo wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 9:29 PM

@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.

Jeffrey Palermo wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 9:31 PM

@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.

Jeffrey Palermo wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 9:32 PM

@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.

hammett wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 11:27 PM

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

Jeffrey Palermo wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 11:33 PM

@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.

Tom wrote re: Objects have dependencies. Methods don't
on Tue, Mar 11 2008 11:55 PM

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.

Jeffrey Palermo wrote re: Objects have dependencies. Methods don't
on Wed, Mar 12 2008 7:14 AM

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.

Dew Drop - March 12, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - March 12, 2008 | Alvin Ashcraft's Morning Dew
on Wed, Mar 12 2008 9:06 AM

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

Jeff Tucker wrote re: Objects have dependencies. Methods don't
on Wed, Mar 12 2008 2:51 PM

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.

Greg wrote re: Objects have dependencies. Methods don't
on Thu, Mar 13 2008 12:18 AM

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>>)

Reflective Perspective - Chris Alcock » The Morning Brew #52 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #52
on Thu, Mar 13 2008 4:08 AM

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

Jeffrey Palermo wrote re: Objects have dependencies. Methods don't
on Thu, Mar 13 2008 9:38 AM

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.

Tom wrote re: Objects have dependencies. Methods don't
on Thu, Mar 13 2008 2:36 PM

"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!

Colin Jack wrote re: Objects have dependencies. Methods don't
on Tue, Mar 18 2008 6:42 AM

"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?

Devlicio.us