Extending Test Frameworks
One really nice feature of TypeMock.NET 4.0 is the ability to extend any/all testing frameworks.
Each test framework has (or lacks) its own extension mechanism, making it hard add extension to all the frameworks. With TypeMock we can now write an new test decorator that will work for all frameworks, including vsTest and nunit, and all runner-tools including TestDriven.NET and ReSharper.
Actually, It is possible to decorate and extend ANY method! As long as it is run with TypeMock enabled. So it is now really simple to implement Roys Enterprise Services to do database testing, and Ian’s Even simpler way for ALL testing frameworks, without rewriting the test framework, extending base classes or forcing ALL tests in fixture to rollback.
We will be able to write the following test:
[Test,Rollback] public void Insert() { //Do some inserts into the DB here and automatically roll back }
Here is the code that does it
[UPDATE: Fixed according to Jonas comment]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class RollbackAttribute : DecoratorAttribute { public override object Execute() { using( new TransactionScope(TransactionScopeOption.RequiresNew)) { // run the test return base.CallDecoratedMethod(); } } }
It is possible to rollback on all tests by decorating the class
[TestFixture,Rollback] public class DatabaseTests { //Do many DB tests here and automatically roll back }
We have implemented the [VerifyMocks] and [ClearMocks] using this technique.
Natural Mocks becoming more intelligent
Natural Mocks automatically mocks everything. This includes return values. So the following code:
using (RecordedExpecations recorder = RecorderManager.StartRecording()) { DummyClass.DoWork(); recorder.Return(new SqlInt32(1)); }
Won’t work as expected because SqlInt32 is being mocked.
This has bugged me a few times and I simply created the return value outside the recorder.
SqlInt32 mockValue = new SqlInt32(1)); using (RecordedExpecations recorder = RecorderManager.StartRecording()) { DummyClass.DoWork(); recorder.Return(mockValue); }
But this is not really nice, and a few customers have pointed out that this could be annoying!
So we are going to implement a feature that will know that you are creating a return value and will not mock it!
This way the first code will work as expected. Of course if you want to return a mocked value you will have to create the mock before, this might lead to non backward compatibility.
To those who want the first code to work as before (although I don’t think that anyone would), mock the return value before calling the recorded statements, and change the above code to:
using (RecordedExpecations recorder = RecorderManager.StartRecording()) { SqlInt32 mock = new SqlInt32(1); DummyClass.DoWork(); recorder.Return(mock); }
Of course if you are going to do that, you will have to define the behavior of the SqlInt32 and you might as well use ChainedMocks
using (RecordedExpecations recorder = RecorderManager.StartRecording()) { DummyClass.DoWork().Value; recorder.Return(1); }
What do you think about this feature?
Design and Testability – YAGNI
After reading Roy’s Post and Oren’s Post who strongly side on Designing for testability I suddenly felt a De Ja Vu.
De Ja Vu
A few years ago, I was managing a project in a big company. One of the features that we where developing was a caching system. We needed the caching to boost performance on a multi location, multi server application.
We developed in a normal Waterfall methodology, and the architect (a really funny and talented guy) came up after a few weeks with his design.
The design was really well thought out and the cache was ready to support – multiple databases with many different kinds of databases along with other things. At the time we believed that we had to design the system with the future in mind.
The question did arise:
Do we need to support Multiple Database Instances?
The Answer was, No, Not really, but if we are going to support it later then the redesign will take us ages.
When I asked the team to read and tell me what they think about: “You Ain’t Gonna Need It“, everyone took this personally. The architect started to feel that his job has been taken away from him:
“I am getting paid to think about future problems” and the developers where also taken aback. They have all been trained to create flexible systems and not flexible processes.
I failed to convince them, and a couple of years later, the caching system became what I call “a black hole”. No one knew exactly how it works, and everyone was scared to change it, because it was soo complex. The developers now said: “We didn’t really need multiple database instance, we spent ages designing and developing this feature, and every bug we find, has to support this feature too, which just complicates matters, because no one uses it but we cannot remove it.”
Still when I talk to them about YAGNI, they all say: “But when we thought ahead and designing the <fill in whatever feature>, we saved weeks and could implement <another featrure> in days. It would have taken us weeks without it”.
I have to remind them that it took months to design, implement and test before we even needed it.
YAGNI, Low Coupling and Testability
So, what has this got to do with Oren and Roy’s posts.
Well, I am getting the same feeling from them that I got from my architect.
Oren, so you found that a “Couple of weeks after introducing the IFileWriterFactory” you found another use for it, and it saved you time.
Good for you!
But this is NOT YAGNI, the opposite. It sounds just like that <fill in whatever feature> that my team was so proud that it had managed to predict.
What about all the other features that have no use? The price of doing this everywhere can be quite expensive. Most of the time (apart from tests) – You Just Ain’t Gonna Need It.
There was a time when we had no choice, you had to either Design for Testability or not test at all. But in these times this is no longer true.
So, Does testing - driving your design, actually create the best design? I am not sure.
It does one thing for sure, It creates a low coupled (modular) design. But low coupling is NOT a silver bullet. A good design has to take and BALANCE many factors, this is a complex task. Adding Testability to these factors might unbalance your design.
Quiz: Which is easier to maintain:
File.WriteAllText(filename, text);
or
using(TextWriter writer = IoC.Resolve<IFileWriterFactory>().Create(filename)) writer.Write(text);
Multiple Asserts in a Single Unit Test
There is a debate going on about having one assertion per test.
James Avery argues that what he’d really like to see in a unit test framework is the ability to run (and fail) multiple asserts within the same test and Roy Osherov still argues that there is value in having one assertion only.
I am less inclined to force a one assertion per test as it might add unneeded burden on the developer, who has to set up the same test scenario for each test. This will require Refactoring the test and Extracting a setup method. On the other hand I would not want the tests to continue to run once the first test has failed, as Roy correctly pointed out, we are in a dirty state.
As we know, there is no Silver Bullet we are going to have to rely on the developers to take the call and decide what is best for them.
I am in favor developers being guided by:
The Test Should Test Only ONE scenario
This does not mean one assert! it means one scenario.
If we need to assert several items to verify that the scenario works, we should do it in the same test (This is how all mocking frameworks work anyway).
In the examples that James brings, each test verifies one scenario but requires several asserts. I believe that this is good practice.
14 facets of TypeMock.NET and Designing for Testability
There has been much talk about Designing for Testability lately.
Basically the argument is:
|
Should our Tests (Enabling Mock Insersions) Drive our design?
or should we use tools to do it for us? |
Here is what 14 of are our community have to say about it:
Still Debating
- Pondering Mocks - Tim Haughton,
Tim is debating Designing for Testability
“On first inspection, I thought this was fantastic… But after my dizzy elation, a sobering thought entered my head. One of the major benefits [is] … that we arrive at very loosely coupled code. This benefit would never occur…” - Stop designing for Testability? – Stewart Robertson
Stu is seeing some logic in using tool to insert mocks but is waiting for backing from the community.
“It does sound very plausible – although it would be interesting to see what other people in the TDD community think – personally I think atm that the need for the extra infrastructure to support our tests is the biggest drawback to developers in our team (D&I)from picking up and running with it. The simpler we can keep it, the less resistance we will get.” - TypeMock – Helps Improve Your Designs? – Colin Jack
Jack debates our questions:
“For me the question is whether designing your code for testability is actually a good idea, if so using TypeMock too much is a bad idea.
Personally I’m much in favor of TDD but I think I disagree with most of the books/Websites because I don’t think that decoupling your code to allow mocking necessarily results in particularly good designs.” - Unit Testing in .NET – Kent Boogaart
Kent talks about the problems of designing for testablility, but has no solution yet.
“I shall continue on my quest for the holy grail by taking a look at TypeMock.NET’s abilities.”
Are basically against using tools except for legacy code.
- Tools instead of testability – Marcus Widerberg
Marcus is debating the issue, with no clear answer yet.
“What I feel is very wrong, however, is using the capabilities provided by Typemock as an excuse to create bad quality, highly coupled and unmaintainable code. When you are starting anew, seize the opportunity! Do it right! “ - Concrete vs. Abstract Type Mocking & Interaction vs. State Based Testing -Paul Eastabrook
Paul Changed his mind and now finds places where TypeMock has value.
“Someone has finally convinced me that TypeMock might not be all bad – chrs OJ. You see, I detest the idea of concrete type mocking, as I strongly feel it misses half the point of mocks, which is discovering class design” - Benefits of Testability – Jay Flowers
Jay believes that writing testable code has great benefits
“TypeMock is a powerful application but I think that it can be misused to allow poor design with ease of unit testing… unit testing and testability are like an alarm indicating early that there is a design problem” - How to mock a static member for test-driven development – Jeffrey Palermo
Jeffrey belives that one shouldn’t use statics, and it is better to redesign your code.
“Using statics all over the place will kill your software. Perhaps you called my bluff when I said “you cannot mock a static.” Ok, you win. My next question is: Do you really _want_ to mock a static?”
Are Pro
- Stop Designing for Testability – The Code Project – .NET – Eli Lopian
Here I talk about the need to isolate you code for higher test coverage and ways to do it.
“Although creating interfaces… is considered a good O/O practice, if taken to the extreme it clutters our code. We should be able to decide what the best design is for the production code without changing it to make our code testable. …so we should STOP kidding ourselves, there is no need to change our design to make our code testable. The Production Code and features should drive our Design not our tests.” - Mock objects: Sealed doesn’t suck as much as it used to – Anders Noras
Andres talks about using sealed classes and unit testing
“Thanks to TypeMock.NET sealed doesn’t suck as much as it used to.” - TypeMock.Net and mocking interfaces using Dynamic Mocking - Adrian Spear
Adrian talks about using TypeMocks to test external components that were not built with mocking in mind
“The main benefit that I have seen so far has been that it is now possible to mock out 3rd party components which were probably never developed with test driven development in mind. I have successfully produced an integration test assembly which we run against each new version of the component we receive which verifies that it still behaves consistently – I can then produce unit tests against all my component client classes with a mocked out component which is very handy to avoid the very time consuming internal initialisation.” - Mocking static methods – Stephan Zahariev’s
Sephan is happly mocking static methods with TypeMock.NET
“Although TypeMock is powerful and easy to use library, there are some disadvantages. “ - unit testing and mocking frameworks – John Spano
John had started to write tests again since encountering TypeMock.NET
“I highly suggest you check it out if you do unit tests, or you were like me and didn’t like them.” - Using TypeMock.NET to mock a external dependency – Maruis Marais
Maruis finds using TypeMock.NET
“Will this ability to easily mock these dependencies now cause us to write code that is more coupled due to the fact that we don’t have to think so much about designing our code with testing in mind? Maybe, it will. But I think that the ability that TypeMock.NET gives us, will help us to write better tests giving us better code coverage and the ability to produce well tested code faster. The only problem is that TypeMock.NET is a commercial product, which will hamper the adoption of the framework.”
Now all you have to do is decide for yourself
TypeMock and TestDriven.NET
| TypeMock.NET and TestDriven are now sold together – for a limited time only. These tool complement each other and using them you can: Write tests with TypeMock.NET and Run them from within Visual Studio with TestDriven.NET I have been working with Jamie Consdale on integrating these tool even more So watch out for more features. |
We are offering a 25% discount for the TypeMock.NET and TestDriven.NET bundle.
Recent Posts
- Product Status Peek – 2011
- Thanks Roy
- Typemock starts 2011 in a new location
- Agile Demos Smells
- I want loud disputes in our meetings
Categories
- .NET Tests
- Agile
- Code Integrity
- Community
- Debugging
- Fun
- Management for Geeks
- Marketing
- Product
- Release
- Reviews
- SharePoint
- TDD
- Time Management
- Uncategorized
- Unit Tests
Archives
- January 2011
- December 2010
- October 2010
- August 2010
- May 2010
- April 2010
- March 2010
- February 2010
- December 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- December 2008
- November 2008
- August 2008
- July 2008
- May 2008
- April 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
