XpdWiki

FrontPage
RecentChanges
XtC
FindPage
PageIndex
XpApprentices

Set your name in
UserPreferences

Edit this page

Referenced by
OpenCroquet
LoD
DoingUnitTesting
LawOfDemeter




JSPWiki v2.0.52


MockObjectsAndDemeter


Brad Appleton describes LoD as follows:

A method "M" of an object "O" should invoke only the the methods of the following kinds of objects:

  1. itself
  2. its parameters
  3. any objects it creates/instantiates
  4. its direct component objects

I guess I am unclear of the statement 'its direct component objects'. Does this mean that a method can aquire a reference to another component? or does a component have to also be passed as a parameter?

I would imagine that means objects that belong directly to "O"

Lets take a EJB application as an example. This application has classes A, B and C that utilize a bean. Each of the classes have 1 or more methods which call the bean directly. Now the question is how do the methods get a reference to the bean. Here are some scenarios;

  1. Each of the classes could have their own factory method that would return a reference to an instance of the bean.
  2. The method itself could lookup the bean and aquire the reference.
  3. The code to aquire the bean could be abstracted into a static class D and the methods could access D directly. Or, D could be a singleton.
  4. The methods could each take a parameter that was the bean.

Option #1 doesn't violate Demeter but is hard to test. Option #2 doesn't violate Demeter, can not be tested and requires even more code duplication. Option #3 violates Demeter (I think) but is easier to test. Option #4 doesn't violate Demeter and is easy to test but requires extra parameter.

Obviously #4 is the best solution. However, is it always practical to pass every collaborating object into the method as a parameter? - GarethReeves

OliBye suggests this is what delegation is for.


Can you give an example from experience of a situation where it's not possible? I can. Where something is statically initialised in an ancestor class. --SteveF
The question is, 'is it always practical?' not 'is it always possible?'. But you have pointed out a case where it isn't possible. What did you do in this case?

It was picking up some resource, so we just had to supply it in the file system. :-(

Yeah, I have had the same issue. If VAJ would store resources in the repository it wouldn't be much of an issue.

Do you structure your code to accept all collaborating objects as parameters? --GarethReeves

Either that or instance variables. It's amazing how far you can go. --SteveF

How do you set the type of the instance variables? We used factory method on the class until so many of the classes required identical factories that we had to abstract them into a static class --GarethReeves


Why do you say that #1 is not testable? Your tests of A, B, C, D can be done by subclassing each of them, and overriding the factory method to return a MockObject instead of the bean.

I'm planning of doing this for the case where my class creates an object that is used and disposed of during the course of a single method... I can't pass the object in as a parameter, and the object is not a member variable of the class-under-test. In other cases, I split a method into two parts, where one creates the object (such as file-reference) and the other method takes that object as a parameter. Now the second method can be tested by passing in a MockObject instead of a file-reference. If the first method does only the actions of creating the object and passing it into the second method, then I can say that it unlikely to break and maybe skip testing it. -- KeithRay?

Yes, you're right and this is what we have been doing with one difference. Instead of subclassing the class we have a setter for the factory, this lets us set the type of class that the factory creates. Subclassing to test has been something that we have been debating recently, I try and avoid it whenever possible. There are two problems that can occur, a sub class could be overriding more than it should be (this can often happen when two pairs are writting tests for the same class at the same time). It is also sometimes hard to see when a test is initializing a subclass instead of a class. Maybe I am just more used to looking for setters on factories. --GarethReeves

Yet one more reason not to use EJB in OliBye's opinion. We use toplink and have a facade which hides toplink (and therefore the database) from our code, but that allows us to unit test that the correct queries are being built. This after all is the only thing we're interested in testing. I know oracle can SQL. Ofcourse we check the queries against oracle in functional tests.

Perhaps we should open a debate on InlineVersusExternalTestCode?. -- MarcuS

The other danger with subclassing for test classes, as TimM discovered, is that you won't have an override when people add new methods later in the parent. There's something I don't quite get here (which may be to do with retrofitting MockObjects) because these approaches seem to be getting more complicated than I'm used to. Can you post a code fragment and maybe we can try to refactor it? --SteveF


There's an interesting question here of what you're testing. If the transient class has a proper test suite, then maybe it's OK to just use it and test the containing class. Depends on the complexity. --SteveF

Yes, I like this question. 'Is it ok to bite off larger chunks to test if the additional parts have their own tests?'. Sorry to repeat the question without answering it. --GarethReeves


Anyone looked at DemeterSoftware?
TellDontAsk


Edit this page   More info...   Attach file...
This page last changed on 22-Nov-2004 13:54:27 GMT by OliBye.