Obviously you have no imagination. You test the same method the same way you test static methods: provide known input, and test that the output is what you expect given the input.
Which is exactly the same way you'd test Math.abs() and numerous other static methods. (Which is exactly the way I test C# extension methods, e.g. http://anonsvn.mono-project.com/source/branches/rocks-playground/Tests/Mono.Rocks.Tests/IEnumerableTest.cs)
To make this "easy", you should attempt to mandate that static methods operate on no mutable state -- following the idioms of functional programming -- or provide some mechanism to reset the global state that the method operates on to a known value.
Remember: global state is also an input to the static method if the method uses the global state.
You can, of course, take this to a "higher level": console input and output is also global state, so if your main method reads from or writes to the terminal, you can have a shell-based unit test which invokes your program (with some set of arguments) and compares the programs output to what was actually generated.
This isn't difficult. Tedious, sure, but not difficult, and extremely useful to do when first starting to write unit tests for a pre-existing project (which may not have used any OO design methodology to begin with).
Just remember the first rule of testing any unit of code (method, library, program, operating system...): check the code's output against known input and compare against known-good output. The rest are details.
Sponge, I believe the point is that any pure method (that relies only on its parameters) can be separated into a pure utility class, leaving less code that depends on the class members.
"Separation of concerns" didn't put a fine point on it, but the goal is to eliminate uneccessary dependencies, much like the Fuel/FuelTank example earlier.
If you see a switch statement you should think polymorphisms. If you see the same if condition repeated in many places in your class you should again think polymorphism.
Could you perhaps give a little code snippet that exemplifies this? That is, what would a switch statement "look like" when turned into a polymorphic solution instead?
maybe examples on how to use polymorphism can be found in the strategy pattern (Gamma 1994). It happens a lot of time (the most when your building some kind of tool/framework) you need to do a generic work (loading database field values into an object, by example), but this generic thing has it's specialties (converting types, converting special values, getting the value, etc). That's when you delegate that special thing (converter.getValueFromBD(...)) and use polymorphism to implement it in various ways (IntegerConverter, ClobToStringConverter, StringConverter, etc, etc, etc).
By the way: strategy is a pattern like template-method except that it preffers composition [using a strategy] than inheritance [overriding the template method]. It illustrate the point about composition vs. inheritance.
There are two ways. None of them use a ServiceLocator.
1) receiving what you need directly in the constructor/setter. I mean: if you need something let your client code give it to you.
new Car(FuelTank)
2) receiving a Provider (NOT A SERVICELOCATOR). It's a subttle diferrence:
A ServiceLocator is bad because it's a general/global entry-point. It's application-aware, not component-aware. So your code becomes less independent.
A Provider (as I propose it) is an interface defined by the very class you are writing and who implements it ONLY does that.
example:
new Engine(FuelProvider)
as I cannot give fuel to the engine directly on the constructor (it's going to ask for it when it runs) I have to give it when the class wants. So that class (Engine) defines the interface FuelProvider:
NormalFuelProvider is more application-dependant that FuelProvider interface. It's fine because it's created for wiring things in an application (assume car is the application). At least, in the example is something that's made for creating a car with an Eingne and a FuelTank.
Getting back to the ServiceLocator what I mean is you can implement a Provider that's aware of the ServiceLocator but your class Engine not.
If you want to test it you can give an AllTheFuelYouWantProvider that do mock-like stuff so you can concentrate on the Engine. You don't have to worry about any ServiceLocator (or FuelTank), don't have to worry about application-like code, and your tests are happier.
This is an interesting article, but the list is rather confusing. Some of the titles are things that you SHOULD do, and some are things that you should NOT do. It is only when you read the body of the list that it becomes clear (and sometimes even then it is not always obvious). I suggest prepending each list item with DO or DONT to make it clear, or rewriting them to make them consistent.
To be specific, all of the points are things you should NOT do, except for 2, 7 and 8, which you SHOULD do.
Build yourself a test fixture using an in-mem database, and add database initialization code to the test fixture class. Sure, it's some overhead, but if you do it right, you only do it once for all DAO tests you write in an application - and IME there are many of them.
Organizing your code into value objects and services is highly non-OO, and was named by (IIRC) Fowler the anemic domain model. I have used it successfully in several LOB apps, but it is specifically damaging when the interactions between your domain-specific objects are rich and complex (like for example in a physical simulation of a system if interacting particles). In such cases, organizing your code into value objects and services rightout harms testability. Therefore I wouldn't include this advice in the list.
@Florin: I do follow your argument about not organizing code into value object and service objects for simulation software.
But my theoretical understand of OO is that an object is Procedural abstraction of Data. That is data being represented purely by its behavior. Service Objects perfectly fit the definition. What is being hidden, is their own state, which should be nobody's concern.
OTH, not all data can be represented by behavior only. In such cases, having a value object makes sense.
Thus IMHO, the advice about dividing the code into Value Objects and Service Objects still seems reasonable.
it's good to see this information in your post, i was looking the same but there was not any proper resource, thanx now i have the link which i was looking for my research.
Good article, most points I agree with. However, there is a strong Java/C# bias in your explanations (or pure OOP bias), and it might be good to stress that fact as some points don't apply as strongly to other languages. Also, this statement made be jump out of my chair:
"Polymorphism: at compile-time the method you are calling can not be determined"
You need to review your basic software engineering knowledge. The definition you give pertains to "dynamic binding", not polymorphism. Polymorphism is essentially the concept of substitutability of types. In other words, being able to substitute one object-type for another and be able to reuse the same method that uses either types is the key aspect of polymorphism (i.e. the object types are polymorphic types and the functions using them are polymorphic functions). This does NOT require dynamic binding, it is only if you need to make this substitution at run-time that dynamic binding is required. Haven't you heard of something called "static polymorphism" (i.e. polymorphism that is realized at compile-time). This also exemplifies my point about the strong OOP bias in your article. I write an enormous amount of procedural code (in C++), heavily relying on static polymorphism, and thus, has a lot of "seams" making the construction of unit-tests very easy (and generally sticking to state-less functional programming is also a huge benefit in that regard). Certainly, in OOP, good use of dynamic polymorphism will make unit-testing a lot easier, but this does not mean that procedural programming (that doesn't use dynamic polymorphism) is hard to unit-test, it's just hard to do so if you suck at writing procedural code.
So overall, I would say that point 6 should be taken out (or left with a strong caveat that this applies only to highly restrictive programming languages that don't allow you to achieve static polymorphism). Then, points 4 and 5 are the same (do you really think anyone who knows what a Singleton is doesn't know that it's forms a global state). Point 3 only applies to languages with reference-semantics with non-deterministic construction models (Java/C# and the like), in a language like C++, this point is mute (unless you are emulating Java/C# style OOP in C++, which is just a very bad style of C++). The remaining points are good IMO.
Continuing on the OOP bias point (Mike December 2, 2011). FP is becoming more and more popular and OO languages allow for more and more of a FP/OOP mix.
If you think about this list in therms of FP, all points are N/A!
In this context, I would like to suggest a shorter list to produce a much more testable code: 1) limit side-effects 2) isolate side-effects
Also, in the context of FP, I very much disagree with point 6. The term 'method' is somewhat redeeming but... A true FP language like Haskell will have a very 'static' feel to it. In OOP/FP hybrid if you want to code with functions instead of methods these functions will need to have static presence too. For example: if 'reduce' is a function that accept an accumulator and a list (instead of being a method owned by the list), it has to exist outside of the list object. I took the approach of using lots of static definitions when designing fpiglet (FP library for Groovy) and I believe it to be some of the most testable code I ever done within the boundaries of an OO language.
RDM vs. ADM ----------------------------------------------------------------
If you separate logic from data in an Object Oriented language, you actually fall back to procedural programming. (A.K.A, by Fowler, "ADM")
Many companies do that for the sake of testing.
However, if you still want to write real Object Oriented and benefit a rich domain model:
1. Separate your project to modules. 2. Each module will have a thin service layer made of stateless logic. 3. Use "new" to instantiate business objects. 4. Use service locator or IoC container to resolve services provided by other modules.
While reading through it, I found some things that sound like typos or minor grammatical errors? I'll post them here, in case you have time/interest to fix them. :) I'll post them into the copy on your blog too.
Thanks! Matt
___ - "OK, you got rid of your new operators in you application code." -> "OK, you got rid of your new operators in your application code."
- "Global state is bad from theoretical, maintainability, and understandability point of view," -> "Global state is bad from theoretical, maintainability, and understandability points of view,"
- "The core of the issue is that the global instance variables have transitive property!" -> "The core of the issue is that the global instance variables have a transitive property!"
- "Seams are needed so that you can isolate the unit of test." -> "Seams are needed so that you can isolate the unit test."
- "If you build an application with nothing but static methods you have procedural application." -> "If you build an application with nothing but static methods you have a procedural application."
- "I don't know how to test application without seams." -> "I don't know how to test an application without seams."
- "How much a static method will hurt from a testing point of view depends on where it is in you application call graph." -> "How much a static method will hurt from a testing point of view depends on where it is in your application call graph."
- "At run-time you can not chose a different inheritance, but you can chose a different composition, this is important for tests as we want to test thing in isolation." -> "At run-time you can not choose a different inheritance, but you can choose a different composition, this is important for tests as we want to test a thing in isolation."
- "This will clutter the focus of test" -> "This will clutter the focus of the test"
- "This helps testing since simpler/smaller class is easier to test." -> "This helps testing since a simpler/smaller class is easier to test."
- "If summing up what the class does includes the word "and", or class would be challenging for new team members to read and quickly "get it", or class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns." -> "If summing up what the class does includes the word "and", or the class would be challenging for new team members to read and quickly "get it", or the class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns."
- "These classes are hard to tests since there are multiple objects hiding inside of them and as a resulting you are testing all of the objects at once." -> "These classes are hard to tests since there are multiple objects hiding inside of them and as a result, you are testing all of the objects at once." ___
I don't know how to unit-test the main method!
ReplyDeleteObviously you have no imagination. You test the same method the same way you test static methods: provide known input, and test that the output is what you expect given the input.
Which is exactly the same way you'd test Math.abs() and numerous other static methods. (Which is exactly the way I test C# extension methods, e.g. http://anonsvn.mono-project.com/source/branches/rocks-playground/Tests/Mono.Rocks.Tests/IEnumerableTest.cs)
To make this "easy", you should attempt to mandate that static methods operate on no mutable state -- following the idioms of functional programming -- or provide some mechanism to reset the global state that the method operates on to a known value.
Remember: global state is also an input to the static method if the method uses the global state.
You can, of course, take this to a "higher level": console input and output is also global state, so if your main method reads from or writes to the terminal, you can have a shell-based unit test which invokes your program (with some set of arguments) and compares the programs output to what was actually generated.
This isn't difficult. Tedious, sure, but not difficult, and extremely useful to do when first starting to write unit tests for a pre-existing project (which may not have used any OO design methodology to begin with).
Just remember the first rule of testing any unit of code (method, library, program, operating system...): check the code's output against known input and compare against known-good output. The rest are details.
"[If your] class has static methods that only operate on parameters [then] you have a class which mixes concerns"
ReplyDeleteI have a class named Importer which has a static method:
Customer ReadCustomer(IDataRecord record)
This method only operates on its parameter. It creates a new Customer object from the IDataRecord.
Could you please describe how this class 'mixes concerns'? I'm not entirely sure how it is doing so.
Miško, in the paragraph about static methods you refer to "seems" - do you mean "seams?" Otherwise I'm not sure what you mean...
ReplyDeleteSponge, I believe the point is that any pure method (that relies only on its parameters) can be separated into a pure utility class, leaving less code that depends on the class members.
ReplyDelete"Separation of concerns" didn't put a fine point on it, but the goal is to eliminate uneccessary dependencies, much like the Fuel/FuelTank example earlier.
If you get past a number of typos and the non-working links, it looks like a hastily written, non-proofed copy.
ReplyDeleteExcellent article! I love seeing these types of topics from this blog.
ReplyDeleteKeep them coming.
You wrote:
ReplyDeleteIf you see a switch statement you should think polymorphisms. If you see the same if condition repeated in many places in your class you should again think polymorphism.
Could you perhaps give a little code snippet that exemplifies this? That is, what would a switch statement "look like" when turned into a polymorphic solution instead?
Max "Could you perhaps give a little code snippet that exemplifies this?"
ReplyDeleteAssume you have a class named "Message" with a method named "sendMessage()" that contains this fragment :
if (this.messageType = messageTypes.Fax) {
...
}
then you should probably have a FaxMessage class that inherits from Message and overrides sendMessage().
@Max,
ReplyDeleteLet's say you are developing a chat service that combines various chat protocols, and you want to implement logout() functionality.
Switch version:
http://pastebin.com/f23bf0c6e
Polymorphic version:
http://pastebin.com/fae7a445
Admittedly, the above example is not the most apt but it is based of a real world refactoring I did a while ago. If you want a more typical example, try http://hanuska.blogspot.com/2006/08/swich-statement-code-smell-and.html
Regards,
Imran Fanaswala
Hm. You have me stumped with the "ask, don't look for" advice.
ReplyDeleteWho exactly would I be asking for the objects I need if I *don't* pass in a ServiceLocator? A global service locator instead?
More about polymorphism:
ReplyDeletemaybe examples on how to use polymorphism can be found in the strategy pattern (Gamma 1994). It happens a lot of time (the most when your building some kind of tool/framework) you need to do a generic work (loading database field values into an object, by example), but this generic thing has it's specialties (converting types, converting special values, getting the value, etc). That's when you delegate that special thing (converter.getValueFromBD(...)) and use polymorphism to implement it in various ways (IntegerConverter, ClobToStringConverter, StringConverter, etc, etc, etc).
By the way: strategy is a pattern like template-method except that it preffers composition [using a strategy] than inheritance [overriding the template method]. It illustrate the point about composition vs. inheritance.
groby:
ReplyDeleteasking:
There are two ways. None of them use a ServiceLocator.
1) receiving what you need directly in the constructor/setter. I mean: if you need something let your client code give it to you.
new Car(FuelTank)
2) receiving a Provider (NOT A SERVICELOCATOR).
It's a subttle diferrence:
A ServiceLocator is bad because it's a general/global entry-point. It's application-aware, not component-aware. So your code becomes less independent.
A Provider (as I propose it) is an interface defined by the very class you are writing and who implements it ONLY does that.
example:
new Engine(FuelProvider)
as I cannot give fuel to the engine directly on the constructor (it's going to ask for it when it runs) I have to give it when the class wants. So that class (Engine) defines the interface FuelProvider:
examples.car.engine.Engine
examples.car.engine.FuelProvider
and somebody implement it how he/she wants:
examples.car.NormalFuelProvider implements
examples.car.engine.FuelProvider
{
// uses FuelTank
}
NormalFuelProvider is more application-dependant that FuelProvider interface. It's fine because it's created for wiring things in an application (assume car is the application). At least, in the example is something that's made for creating a car with an Eingne and a FuelTank.
Getting back to the ServiceLocator what I mean is you can implement a Provider that's aware of the ServiceLocator but your class Engine not.
If you want to test it you can give an AllTheFuelYouWantProvider that do mock-like stuff so you can concentrate on the Engine. You don't have to worry about any ServiceLocator (or FuelTank), don't have to worry about application-like code, and your tests are happier.
interesting article
ReplyDelete@Imran and @Michel:
ReplyDeleteThanks! This seems like something I've done for a while without knowing what it was called. I appreciate the explanation!
This is an interesting article, but the list is rather confusing. Some of the titles are things that you SHOULD do, and some are things that you should NOT do. It is only when you read the body of the list that it becomes clear (and sometimes even then it is not always obvious). I suggest prepending each list item with DO or DONT to make it clear, or rewriting them to make them consistent.
ReplyDeleteTo be specific, all of the points are things you should NOT do, except for 2, 7 and 8, which you SHOULD do.
If you have a spring project and you want to test a dao - how do you do that *easily*.
ReplyDeleteEveryone just says, "use dbunit".
But I don't see how that makes it easy.
Build yourself a test fixture using an in-mem database, and add database initialization code to the test fixture class. Sure, it's some overhead, but if you do it right, you only do it once for all DAO tests you write in an application - and IME there are many of them.
DeleteOrganizing your code into value objects and services is highly non-OO, and was named by (IIRC) Fowler the anemic domain model. I have used it successfully in several LOB apps, but it is specifically damaging when the interactions between your domain-specific objects are rich and complex (like for example in a physical simulation of a system if interacting particles). In such cases, organizing your code into value objects and services rightout harms testability. Therefore I wouldn't include this advice in the list.
Delete@Florin:
DeleteI do follow your argument about not organizing code into value object and service objects for simulation software.
But my theoretical understand of OO is that an object is Procedural abstraction of Data. That is data being represented purely by its behavior.
Service Objects perfectly fit the definition. What is being hidden, is their own state, which should be nobody's concern.
OTH, not all data can be represented by behavior only. In such cases, having a value object makes sense.
Thus IMHO, the advice about dividing the code into Value Objects and Service Objects still seems reasonable.
Is my reasoning incorrect?
About Singletons, I completely agree. I posted this article on my blog: http://prettyprint.me/2009/06/24/beware-of-the-singleton/
ReplyDeleteExcellent topic and content. Keep them coming
ReplyDeleteIf I could wrap my head around it, I"ll try :).
ReplyDeleteit's good to see this information in your post, i was looking the same but there was not any proper resource, thanx now i have the link which i was looking for my research.
ReplyDeleteGreat article. I tried for one hour+ to make this point to a colleage y-day. I'll just send her this article.
ReplyDeleteGood article, most points I agree with. However, there is a strong Java/C# bias in your explanations (or pure OOP bias), and it might be good to stress that fact as some points don't apply as strongly to other languages. Also, this statement made be jump out of my chair:
ReplyDelete"Polymorphism: at compile-time the method you are calling can not be determined"
You need to review your basic software engineering knowledge. The definition you give pertains to "dynamic binding", not polymorphism. Polymorphism is essentially the concept of substitutability of types. In other words, being able to substitute one object-type for another and be able to reuse the same method that uses either types is the key aspect of polymorphism (i.e. the object types are polymorphic types and the functions using them are polymorphic functions). This does NOT require dynamic binding, it is only if you need to make this substitution at run-time that dynamic binding is required. Haven't you heard of something called "static polymorphism" (i.e. polymorphism that is realized at compile-time). This also exemplifies my point about the strong OOP bias in your article. I write an enormous amount of procedural code (in C++), heavily relying on static polymorphism, and thus, has a lot of "seams" making the construction of unit-tests very easy (and generally sticking to state-less functional programming is also a huge benefit in that regard). Certainly, in OOP, good use of dynamic polymorphism will make unit-testing a lot easier, but this does not mean that procedural programming (that doesn't use dynamic polymorphism) is hard to unit-test, it's just hard to do so if you suck at writing procedural code.
So overall, I would say that point 6 should be taken out (or left with a strong caveat that this applies only to highly restrictive programming languages that don't allow you to achieve static polymorphism). Then, points 4 and 5 are the same (do you really think anyone who knows what a Singleton is doesn't know that it's forms a global state). Point 3 only applies to languages with reference-semantics with non-deterministic construction models (Java/C# and the like), in a language like C++, this point is mute (unless you are emulating Java/C# style OOP in C++, which is just a very bad style of C++). The remaining points are good IMO.
Just my grain of salt.
Do you test the code that creates the object graph? If so, how?
ReplyDeleteHow does one deal with dynamically created objects (say) like objects representing email?
ReplyDeleteI guess "branches" would be the correct term as opposed to "seams".
ReplyDeleteContinuing on the OOP bias point (Mike December 2, 2011).
ReplyDeleteFP is becoming more and more popular and OO languages allow for more and more of a FP/OOP mix.
If you think about this list in therms of FP, all points are N/A!
In this context, I would like to suggest a shorter list to produce a much more testable code:
1) limit side-effects
2) isolate side-effects
Also, in the context of FP, I very much disagree with point 6. The term 'method' is somewhat redeeming but...
A true FP language like Haskell will have a very 'static' feel to it. In OOP/FP hybrid if you want to code with functions instead of methods these functions will need to have static presence too. For example: if 'reduce' is a function that accept an accumulator and a list (instead of being a method owned by the list), it has to exist outside of the list object. I took the approach of using lots of static definitions when designing fpiglet (FP library for Groovy) and I believe it to be some of the most testable code I ever done within the boundaries of an OO language.
RDM vs. ADM
ReplyDelete----------------------------------------------------------------
If you separate logic from data in an Object Oriented language, you actually fall back to procedural programming. (A.K.A, by Fowler, "ADM")
Many companies do that for the sake of testing.
However, if you still want to write real Object Oriented and benefit a rich domain model:
1. Separate your project to modules.
2. Each module will have a thin service layer made of stateless logic.
3. Use "new" to instantiate business objects.
4. Use service locator or IoC container to resolve services provided by other modules.
Thanks for the article. Awesome tips!
ReplyDeleteWhile reading through it, I found some things that sound like typos or minor grammatical errors? I'll post them here, in case you have time/interest to fix them. :) I'll post them into the copy on your blog too.
Thanks!
Matt
___
- "OK, you got rid of your new operators in you application code." ->
"OK, you got rid of your new operators in your application code."
- "Global state is bad from theoretical, maintainability, and understandability point of view," ->
"Global state is bad from theoretical, maintainability, and understandability points of view,"
- "The core of the issue is that the global instance variables have transitive property!" ->
"The core of the issue is that the global instance variables have a transitive property!"
- "Seams are needed so that you can isolate the unit of test." ->
"Seams are needed so that you can isolate the unit test."
- "If you build an application with nothing but static methods you have procedural application." ->
"If you build an application with nothing but static methods you have a procedural application."
- "I don't know how to test application without seams." ->
"I don't know how to test an application without seams."
- "How much a static method will hurt from a testing point of view depends on where it is in you application call graph." ->
"How much a static method will hurt from a testing point of view depends on where it is in your application call graph."
- "At run-time you can not chose a different inheritance, but you can chose a different composition, this is important for tests as we want to test thing in isolation." ->
"At run-time you can not choose a different inheritance, but you can choose a different composition, this is important for tests as we want to test a thing in isolation."
- "This will clutter the focus of test" ->
"This will clutter the focus of the test"
- "This helps testing since simpler/smaller class is easier to test." ->
"This helps testing since a simpler/smaller class is easier to test."
- "If summing up what the class does includes the word "and", or class would be challenging for new team members to read and quickly "get it", or class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns." ->
"If summing up what the class does includes the word "and", or the class would be challenging for new team members to read and quickly "get it", or the class has fields that are only used in some methods, or class has static methods that only operate on parameters than you have a class which mixes concerns."
- "These classes are hard to tests since there are multiple objects hiding inside of them and as a resulting you are testing all of the objects at once." ->
"These classes are hard to tests since there are multiple objects hiding inside of them and as a result, you are testing all of the objects at once."
___
Fixed! Thanks!
ReplyDelete