A colleague of mine,
Siva post a short blog entry
Mocks are evil!, which became very interesting debate about OO programming and design, how we thing about verifying and designing our objects as well as the standard argument about Mocks or Stubs. I think that it is very interesting debate that I will repost on my blog as well. Siva is arguing that using Mocks is not always the best thing to do. I completely agree with that but I disagree about the importance of state testing for good OOD.
Siva said: Mocks are evil! -------------------------------------------------------------------------------------------------Igor said... This could be seen in two ways:
1) We are testing the implementation rather than verifying behavior. And this is exactly what we do. Example, my method should call dao in order to persist to db. I don’t want to know if we actually persist the object, I just want to now whether particular method of the INTERFACE of the dao is called. Interface identifies behavior. That’s why I want to verify this behavior.
2) As our interactive based tests are tied to implementation, refactoring becomes a pain. Refactoring will take more time as we need to fix interactive based tests.Since we don’t care about the actual implementation of the method, this could save us a lot of troubles when we change, refractor or substitute different objects (implementation) for the tested interface method. If we have problems with the mocks when we refractor, this means, the behavior has changed and that is what we are testing. If we don’t care about the behavior then we are probably better off with stubs.
3) It puts us in wrong perspective. Instead of thinking in terms of behaviors in our unit (tests / contexts) we end up thinking about implementation like whether this method calls that method.If you use real object, then you think about the state of this object and not for their behavior, which is no any different than thinking about db tables.
Otherwise, I feel your pain. Probably, we should use them more rationally.
-----------------------------------------------------------------------------------------------------
Siva Jagadeesan said... I don’t want to know if we actually persist the object, I just want to now whether particular method of the INTERFACE of the dao is called.
Igor I accept with u. This above scenario is a good example for interactive based testing.
Take this code snippet for example.
public void doSomethingAndSave(){
doSomething();
getDao().save();
}
For the above method, we might have these following behaviors to verify.
Behavior 1) shouldCallDaoSave
Behavior 2) shouldDoSomething
Behavior 1 is perfect for using interactive based testing. By using mock we could avoid going to database.
In behavior 2, we do not care whether it is calling getDao().save(), all we want to verify is whether it is doing “something" that we specify. In this situation state based testing is better than interactive based testing. By using dummy stubs, we do not have to change this behavior even if we decide not save anything after doing “something”. But if we used interactive based testing for this behavior, then we would have to fix this behavior (even though nothing has changed in behavior that it specifies) when we refactor this method not to save anything.
------------------------------------------------------------------------------------------------
Igor said... In 1) you are interested in how the dao will behave. That’s when you need a mock to verify its behavior as you pointed out.
In 2) you have behavior specification that tests exactly “doSomethingElse”. So, in this case you don’t need to mock dao because you don’t verify its behavior. You should have one assert/verification per test, so you testing/verifying the dao at all. You just need to stub it. However, I don’t think that state testing has anything to do with this situation. If you stub it, you don’t check for the state at all.
I believe that state testing is not good approach to OO design. It makes us think in terms of data holders (aka db tables) instead of thinking about object behavior and object collaboration. Since, one of the principles of OOP is hiding the state of the object and providing specific behavior, we should avoid thinking of the state of the object. That’s one of the major reason why most of the object that we see are data holders with public getters and setters. I would prefer to see object without any public getter or setter rather with methods giving me some behavior.
So in summary, I completely agree that we should use mock with great deal of consideration. Also, most of the times stubs would be more appropriate. Yet, don’t confuse using stubs with state testing. I completely disagree that state testing can be any good for OOP.
----------------------------------------------------------------------------------------------------
Siva Jagadeesan said... Igor I agree with you :)
Quote from Martin’s article about state based testing,
“…kick your primary object with the behavior you want to test. Once it's done you then need to find out if everything went well. This you probe by using a bunch of assert statements, both against the primary object…”
http://www.martinfowler.com/articles/mocksArentStubs.html#State-basedTestingIn my article I am not advocating State based testing… I am more concerned about verifying behavior of an object. How we verify behavior depends on framework we use. If we use Junit, unfortunately we have to verify behavior by asserting the state of object.
I have not looked at JBehave, it will be interesting to see how this framework enables us to verify the behavior of object.
------------------------------------------------------------------------------------------------
Igor said... Martin’s article is classic but it is a little outdated already. As I pointed out, I don’t think that state base testing brings value for creating good OOD. (Probably for QA testing yes, but not designing).
You can use JUnit with EasyMock or JMock and verify behavior without any problem. It is not design to verify behavior but with a little more effort you can achieve Behavior Driven Design with JUnit as well.
I agree on everything else besides the testing of the state of an object. Since the state should be encapsulated inside of the object, I don’t think that trying to test it will evolve to a good Object Oriented Design. You shouldn’t be allowed to ask an object for its state; rather you should delegate some responsibility to an object and verify whether it perform it correctly.
----------------------------------------------------------------------------------------------------Siva Jagadeesan said... You can use JUnit with EasyMock or JMock and verify behavior without any problem. It is not design to verify behavior but with a little more effort you can achieve Behavior Driven Design with JUnit as well.
Using EasyMock or JMock with Junit , we will be still testing implementation not the behavior.
I agree on everything else besides the testing of the state of an object. Since the state should be encapsulated inside of the object, I don’t think that trying to test it will evolve to a good Object Oriented Design. You shouldn’t be allowed to ask an object for its state; rather you should delegate some responsibility to an object and verify whether it perform it correctly.
Lets take classic object Lamp.
public class Lamp {
private boolean on;
public void switchOn(){
setOn(true);
}
public boolean isOn() {
return on;
}
private void setOn(boolean on) {
this.on = on;
}
}
Might be I am missing something here. How can we make sure “switchingOn” behavior worked correctly without verifying the state (on/off) of Lamp?
-----------------------------------------------------------------------------------------------
Igor said... This example is very similar to the problem that they describe in famous article about OOD - “The Mark IV Special Coffee Maker”.
http://www.objectmentor.com/resources/articles//resources/resources/articles/CoffeeMaker.pdfWe are writing a program here, and programs are about behavior! We should think about behavior. What is the behavior in class Light? It is the behavior of a system that is the first clue to how the software should be partitioned.
Clearly, from you design the Light object just wants to be turned on or turned off. Thus we might put :
void switchOn();
void switchOff()
method in class Light. I think that the return value of these methods is the problem here.
So, if the behavior that you want is to swtichOn the light and then verify that everything went successfully:
public interface Switchable{
boolean switchOn();
}
public class Lamp implements Switchable {
public boolean switchOn(){
//implementation that we don’t care
}
}
Behavior Specification will look like this.
public void shouldSitchOnTheLightSuccesfullyWhenEverythingIsOk(){
Ligh light = new Light();
shouldBeSuccessfull(ligh.switchOn());
}
That’s it. I don’t need to check the state of the light in order to verify that the behavior specification of this object.
Later on, if you need additional behavior to check whether the light is on you can add the other method:
public boolean isOn();
However, do you really want to know that? I would try to avoid this method since “One of the core tenets of object-oriented programming is encapsulation. It’s one of OO’s most powerful ideas. More powerful than inheritance. Unfortunately it’s also one of the most ignored.” From Dave Astels’s blog:
http://blog.daveastels.com/?p=55.
If you put isOn() method just to test switchOn() without actually needing it then you reveal to much from your code without needing it. From the pragmatic guys
http://www.pragmaticprogrammer.com/articles/may_04_oo1.pdf:
“The best code is very shy. Like a four-year old hiding behind a mother’s skirt, code shouldn’t reveal too much of itself and shouldn’t be too nosy into others affairs.
But you might find that your shy code grows up too fast, shedding its demure shyness in favor of wild promiscuity. When code isn’t shy, you’ll get unwanted coupling.”
Your testing and behavior specification are tightly coupled to the implementation of Light object. “This is a classic approach from the old days or procedural programming. It is NOT OO. This is just one example of the approach of treating objects like new age data structures: Ask an object for information about its state, process that, make decisions based on that, then do something to/with the object.” (Astel’s)
All we should know is how to ask the light to turn on and whether it went successfully.
The proper approach is to ask the Light to turn itself on. Let me know if you were able to do that. We don’t care about it state at all.
This is a little aside but:
“As a side note, writing code this way makes it much more understandable.” (Astel’s)
Also, from Dave Astele’s brilliant article about Behavior Driven Design (BDD)
http://daveastels.com/files/sdbp2005/BDD%20Intro.pdf:
“First stop thinking in terms of tests. As Bob Martin has been saying for a few years “Specification, not Verification”. What Bob means is that verification (aka testing) is all about making sure (i.e. verifying) that your code functions correctly while specification is all about defining what it means (i.e. specifying) for your code to function correctly.”
So based on the above, if you argue that in my behavior specification I would not be sure whether the light is actually turned on right now (verify that my code works correctly), I would say that I just want to now that light has been turned on successfully (not exactly interested if it is on right now.)
Anyway, this debate is going on for the last 10-12 years of OOP, so I think will continue have arguments about that. Still, if we care about the state than what is the difference between OOP and database.
-----------------------------------------------------------------------------------------------------
Siva Jagadeesan said... Igor it is a great explanation. I think my problem is my state of mind. Even though I am familiar with OOP concepts, I am relaxing those OOP rules to make it testable. This is wrong. I should consciously do behavior driven design.
Instead of State Based Testing, how about Behavior Based Testing?
---------------------------------------------------------------------------------------------------------
Igor said…P.S. After Siva contacted Martin Fowler about all that, he stated that he is still unconvinced about this style of testing since mock verification couple a test to the implementation of the object under test. So, I have to say the article “Mocks aren’t Stubs”, from which I learned a great deal about design and testing as a whole is not outdated. Rather, my view about object state testing has changed a lot since I read this invaluable article and I tend to have different opinion on that now.
Thanks to Martin for his significant input on that topic and his replay.
Siva, thanks for the interesting topic and exciting debate.