Unit Testing, Agile Development, Leadership & .NET - By Roy Osherove
You know what I'd love to see you post is a code sample using the natural mocks syntax and one using the "full power" syntax.
It sounds like you're saying the programming model for writing tests using one approach vs the other in TypeMocks are different enough that you know when you're doing one thing or the other.
In other words, if you're writing new code, you won't "accidentally" be able to test something that's normally not testable by accident, thus perhaps cutting off an extensibility point. You have to consciously choose to use the more powerful approach for testing something like legacy code.
Is that a fair characterization?
Old decision process
-Design some functionality that requires a single instance of something
-I will use a static class
-I want to test something that consumes the single instance
-Oh wait I can’t mock a static class
-I better use settable singleton or dependency injection through configuration.
Now it works but is more complicated because I need to make it testable
Decision process with TypeMock
-I will mock the static class using type mock
Now it works with no custom dependency injection framework or other code.
Do you understand what I am getting at? How can the logic be “don’t use TypeMock because that is not designing for testability”? TypeMock is facilitating that testability. If you can test something with TypeMock you are by definition designing for testability.
Now the only bad thing is that you are tying yourself to a testing tool. But that is the case no matter what tool you use. Each can facilitate you testing different things. Does “designing for testability” really mean “Design for testability if u only have the simplest toolset to help you”?
In order to avoid the FUD problem you can use the following:
• Use different GUI presentation (icon, color, ext…) for test that may not apply to the TDD (and It can have different level from best practice to mal practice)
• Filter the test by their best to mal practice category so the tester can write any kind to test but the architect can validate upon the tests that will not bypass the TDD
I think everything you have said is correct, with a small proviso:
"If you were doing bad design before, the tool won't help you, just the technique"
The issue is with people just picking up TDD or mocking. They see that there is a way to mock a static class, and do it. The thought never occurs to them that it probably shouldn't be there in the first place. And because of that, when you try to then say "well I prefer to use an IoC container here to remove this dependency", they use the test as a justification of why you dont need to invert it, after all if we don't need to do it for testability, and our application probably won't have that logic replaced in future, why bother? We can just use the clever trick that TypeMock does if we *ever* see a need to replace it.
This pretty much comes from a paraphrase of a real example where I am working right now - where resistance to good design principles, and TDD, and mocking is pretty high. I think TypeMock would make some of my code *much easier* to test (where it depends on systems like MOSS), but for our own code I could see it being abused frequently.
It is that tricky balancing act to play - give people all the power in the world and trust them to use it safely, or don;t let them have it until they have a business (and technical) argument for using it.
I love this quote "lose sight of design decisions about making the code testable in the first place". To me this sums up what I perceive as a huge problem with many people in the current Agile/XP world: creating testable code is a means to an end, it is not the ultimate goal. The easier it is to create testable code (because the testing tools are better), then I have more freedom to choose the best design to solve the business problem, instead of trying to find the best design to solve the testing problem. The two concepts are not the same.
The real compelling argument for TypeMock is the legacy code argument. When I starting a new project, I would probably pick Rhino.
For me, this is about using the right tool for the right job. For new development, I find RhinoMocks to be the right tool. But, I've done enough with legacy code to know that having the functionality that TypeMock provides is very useful when working against someone else's libraries that were obviously not written with testability in mind.