I always wanted to read some comprehensive book on unit testing, therefore book “The Art of Unit Testing: With Examples in .Net” appeared in my list of books to read. It has been more than 1 year since I planned to read it, finally it took me only 2 days to read it – yesterday and the day before yesterday. Sometimes comprehensive things are not that comprehensive as you imagine them or… maybe with time topic is no longer that vast for you.
Nevertheless, I remember my first months of my first job as Software Developer. During one of my first team meetings question of failed Unit Tests was raised. Our clients were really concerned about quantity of tests and reasons behind tests failing during nightly builds. I clearly remember that passionate discussion and someone saying “… or are there guys who don’t know what Unit Test is?” and loud laugh after that. I made smile on my face. I maybe heard once or twice about such combination of words, resulting in abbreviation UT, but it didn’t ring a bell. I wasn’t brave enough to ask. Now I think I wasn’t one in that room who didn’t know, otherwise why would we had problems in the first place?
Because of coincidences and my eagerness, when I was about to leave many considered me as internal expert in Unit Testing. No surprises, I have many posts on UnitTesting.
Reading this book forced me to think twice about some of the testing techniques I use. Probably I changed my mind about some code I write, both in test and outside. I took some notes for myself.
Good indicator if book is for beginners is if it has something like “right click on…” – Yes, this book has few mouse clicks.
Roy introduces many definitions. Some of them are bit contradictional. For example, it might look like there are fakes, stubs and mocks while reading the book, but at some point of time you read this “A fake is a generic term that can be used to describe either a stub or a mock object (handwritten or otherwise), because they both look like the real object.” At least Martin Fowler thinks that fake is different from stub and mock. It is something I also don’t like about definitions in UnitTesting, they are blurred. Every faking mocking framework has its own interpretation and word “mock” is too much overloaded.
As per me, there are some things, which might look not completely professional for the book writer. I mean phrases like this one: “When all else fails and your code is hard to test, you have three choices: use a “super” framework like Typemock Isolator, change the design, or quit your job.” I hope you know why Typemock is highlighted as well. :)
Sometimes stuff is over explained. For example, “One test calling another breaks isolation and introduces a dependency” and then goes explanation why this is bad idea with lots of bullet points. Well, I wouldn’t even think about mentioning stupidity of doing such things.
Book “Working Effectively with Legacy Code” is referenced really often. It worth reading it. I even have hardcopy of it, but only read few pages.
Book is really easy to read. It is straight, well structured and formatted. I enjoyed reading it.
Caution: this list is my personal, for you it might look completely different.
– I tend to write extremely testable code, which often results in overengineered design with low percentage of “private” code. Roy recommends to not test methods, which are better left private to code under test.
– Stop overspecifying unit tests.
– One mock per test. I would like to violate this rule less frequently.
– Ideally one assert per test.
– Think more about applying some global testing techniques, like separation of integration tests from unit tests, or fast from slow, etc.
– Utilize more syntaxes and capabilities of testing/mocking frameworks.
Do I recommend the book?
In short, YES. If you are just starting with Unit Tests this book is excellent for your learning and I highly recommend it. If you have developers in your team who need to learn Unit Testing give them this book. Finally, read it yourself, at least scroll parts 1 and 2, read part 3 and slowly scroll part 4.
I’m not going to write a long post discussing advantages and disadvantages of high code coverage. There are hundreds if not thousands of such posts out there and in the end almost all of them conclude that high code coverage in general is nice but not always justifiable, one of main reasons being redundant abstractions in favor of higher coverage. Here are my recent thoughts.
It may sound crazy and not doable at all(*) or may have side effects if misused. I suggest very simple techniques to achieve high code coverage the right way:
Don’t be lazy. Recently I worked on a project and I already had 95% coverage. If I haven’t decided to increase coverage further I wouldn’t have found one missing mapping for a property. I maybe spent couple of hours to write more tests, instead of days of devs/testers/managers time to work around the bug. And in case of finding this in production it would cost real money for the company.
Work around external dependencies you really cannot test. Isolate them as much as you can and simply exclude from coverage report. I don’t think this is cheating. It is the best you can do, plus you do it explicitly. And, of course, you should have integration tests to test external dependencies.
Remember the Single Responsibility. Well… and few more things. You will be amazed how much code is simpler and easier to read if you just keep following SOLID. I think that developer should be able to clearly describe responsibility of a single class within one sentence.
Start with testing in mind, not with coverage number. It is vital to keep in mind that tests are intended to ensure you code works as designed and without defects, tests are NOT intended for high coverage numbers, which can be shown to boss. Thus always have tests to cover more important and sensitive code at first and only then move towards covering less important or easy to test code.
Refactor! Never write code you don’t like. It is fine to hate it the next day, but not at the moment when you are writing it. Usually crap code starts to appear when you try to add functionality which was not planned before. You must refactor constantly (same is applicable for your unit tests). Keep everything in synch.
Be a 100% good programmer. Don’t spoil yourself with 80% coverage or with just 60%. If someone says you are 75% good programmer, would you like it? Well, it is high number, isn’t it? I was worse developer few months ago than I’m today. Year ago I would disagree with today’s myself. High coverage, if used right, means that you know that your code works and that it is readable/refactorable/decoupled/structured/… and most of all – it is highly maintainable.
I hope my opinion sounds sensible!
Till next time…
There are research papers on this matter. In “Experiments of the effectiveness of dataflow and control flow-based test adequacy criteria” authors “evaluate all-edges and alluses coverage criteria using an experiment with 130 fault seeded versions of seven programs and observed that test sets achieving coverage levels over 90% usually showed significantly better fault detection than randomly chosen test sets of the same size. In addition, significant improvements in the effectiveness of coverage-based tests usually occurred as coverage increased from 90% to 100%.” – from MS research paper.
(*) I could agree with many exceptional situations you are thinking about. I would agree that with old systems it is difficult to do what I ask you to, I would also agree that if there are deadlines it is hard to stand against. There are bad programmers around, bad decisions taken and many other conditions. In the end it is your job to do the job right. And if you cannot, change the company or change the company.
If you are building Windows Phone application you probably have faced… well… not rich support for unit testing. But of course there is one rescuing thing – WP7 is almost the same Silverlight application. Thus you have wider area to search for solution. Awesome… but I wouldn’t write this blog post if everything is that easy. Right?
Microsoft for some reason doesn’t care about huge community of those who use NUnit for their projects, and believe me not for small projects. So there of course is mstest project template that allows you to run tests inside of the appropriate CLR. There is good Silverlight Unit Tests Framework and here is information on how you can cheat in order to get it working for the phone. Problem with these two frameworks is obvious – they are not supporting console – they run in native for Silverlight environment – either on phone or in web. See pictures (phone and web respectively):
I know that there are ways to make it happen from console under (msbuild for example this temporary wp7ci project on codeplex). Hold on… one second. Again something very specific to Microsoft – msbuild. But what if I’m using nAnt?
I came up with odd solution to force nunit-console to run unit tests in command line. After I observed it crashing with error TargetFrameworkAttribute I reflected mscorlib and googled a bit to discover this attribute exists in mscorlib of 184.108.40.206 version, but nunit actually targets 220.127.116.11 one (.net 2.0). Thus I decided to download sources of NUnit and recompiled those against .net framework 4.0 (mscorlib 18.104.22.168). Reason for this error is that Silverlight also uses higher version of mscorlib.
Before upgrading to Mango our tests for WP7 were created by testDriven (to be honest – it is what they use inside of their SUTF). We didn’t have support for command line and tests were running only because they are so Silverlight compatible.
With updating to Mango everything just died. Tests projects simply didn’t get loaded into solution. With this message:
“Not a big deal” you say. Actually a big deal, because you can get rid of this message by editing project files to have target framework profile set to WP71 and to reference only WP71 assemblies. But in this case you lose all of you compatibility with Silverlight and when you run your tests you start to get weirdest exceptions in the world like this one below:
System.DivideByZeroException : Attempted to divide by zero.
At least this brings some more sense:
System.InvalidProgramException : Common Language Runtime detected an invalid program.
Solution I came up with is not 100% right, but at least it works. I just had to pretend that I’m still completely compatible with Silverlight. So I created copy of my project. One is considered to be used from command line and other for usage from VS.
Project 1 is used under VS has correct references directly to WP71 assemblies, like below:
This ensure that VS loads your projects without errors, also you make it think it is WP7 by these:
<Import Project="$(MSBuildExtensionsPath)MicrosoftSilverlight for Phone$(TargetFrameworkVersion)Microsoft.Silverlight.$(TargetFrameworkProfile).Overrides.targets" />
<Import Project="$(MSBuildExtensionsPath)MicrosoftSilverlight for Phone$(TargetFrameworkVersion)Microsoft.Silverlight.CSharp.targets" />
Project 2 is used for console and is pretended to be pure Silverlight, so it has:
Which in reality copies (because of <Private>) wrong assemblies – from Silverlight, not from phone.
You would need to play a lot with which assemblies you want to get in folder where you run tests. I do have some confidence that Silverlight and WP7 are much compatible thanks to this brilliant explanation of what is WP7 from developer’s view.
At #1186 I finally got build working and running tests. At #1193 I invented this Silverlight pretending trick. And finally till build number #1196 I ignored couple of incompatible tests and fixed some really failing tests.
Hope this helps someone. At least it is going to help my team.
Couple of days ago I’ve been on CI seminar, where guy had been talking about concepts of the Continuous Integration and at some moment mentioned about testing environment and it suddenly dawned upon me and I would like to share my thoughts on this.
Two of many concepts of the CI are:
Feel the difference?
Ok, why do I ask about this?
Maybe a week ago we’ve moved to approach that builds sources and runs unit tests on absolutely virgin machine. Simply saying, nothing is installed into GAC, except of maybe .net framework. Everything needed we take from library folders under source control. And I agree that is really good thing. Compiler is also ok to build projects when they have reference only to root assembly in folder of other assemblies of some particular component. BUT, when you execute your code (run tests) CRL tries to find assemblies in execution folder and then in GAC. Since we have nothing in GAC, we should ensure that everything gets copied to execution folder, and here we dive into issues.
In case of simple referencing this is not a big issue. You just should be as a spider and catch what is missed on enigma CI build machine. In some cases this is very trivial – you see System.IO.FileNotFoundException, in other cases it is not obvious.
Here is one of tricts that we were needed to apply to make UT happy:
Since dll-s like sqlceme.dll are part of SQL CE, but are not CLR dlls we cannot reference them. So we add them as link in your project and then change Build property to “Copy Always” to have them in bin.
There were some other tricks we were needed to try. They are simple, but there are many.
Main Question is still remaining
All that is not main intent of this post. Main is this: Do I really need to do this. Why is this correct?
And if we are so dedicated to CI, then I would like to know also what are we testing? That our code is able to run even if none of 3rd party components are installed?
I still have some doubts, maybe I’m wrong. I would really appreciate any of your thoughts, comments that will help me figure it out and find the right way.
For fun (but maybe will get lucky) I also asked Martin Fowler in twitter:
Few days ago I worked few hours on Sunday, so there were only me and one of my co-workers in the room. He is Delphi guy, but likes to learn .NET. He had to implement some custom resizing logic for the report and he asked me if I can help to think on the logic. We had spent maybe couple of minutes before we got some preliminary ideas.
Let’s do Pair Programming
We decided to implement some prototype/logic within .net. I suggested pair programming with TDD: “I will be writing tests – you will be implementing logic to make them work”. BTW, do you know how do we call this particular programming pattern? – It is called “Ping-Pong Pair Programming“.
So after I created basic test project and wrote a test that simply has something like “var report = new Report();” and then “report.Draw();“, which of course is failing UT, he proceeded with creating class for Report and putting in place stub method Draw. Then I added functionality that allows adding report columns, then sizing of them, desiredMinimalWidth and delimiting width. Then UT that verifies if we correctly resize columns, if they fit or do not fit into report. Misha was performing extremely well in implementing logic, we had been thinking on. At some point of time he got stuck, so we continued together on making latest UT work.
I enjoyed this try of doing Pair Programming along with TDD.
What are benefits of doing PP as per me?
Are there disadvantages?
It might happen that PP will not be feasible, especially in situations when problem they are trying to solve is trivial or when one of contributors is not interested in going great job. You can read lot of discussion over the internet about the time PP consumes and the quality of the work. Most commonly you will hear that when doing PP it takes +15% of time if two developers work independently and produces 15% fever bugs.
What are preconditions on doing Pair Programming as per me?
In my further professional growth I will try to involve more people in this practice!
Today, I’ve been writing few methods for my DAL classes, of course, I decided to have one or few integration unit tests that hits database and see actual SQLs with NHibernate Profiler.
So in couple of minetes I’ve got unit tests that had following line in the beggining of each:
if you don’t know, this line attaches your execution code with NHibernate Profiler, so I’m able to see SQLs NHibernate generates.
When I run bunch of unit tests in my testing file, I’ve got strange picture with duplicating of queries for each test with arithmetic progression. And N+1 problem, but hold on, I’m sure that I did everything through joins.
Reason is that profiler appends to my code on each new test run and that is why it start thinking that I have multiple selects to get list of something.
Solution, which I would recommend as pattern for writing Unit Tests with NHibernate Profiler is following:
Are you married? Yeah, quite not usual question for blog post about mocking, but if you are married you probably asked your girl to become your wife.
So you are playing role of PotentialHasband:
and she is PotentialWife, taking your ask into consideration and answering you true or false.
If she is Linda, you would need to have “I love you” in your speech to get her agreement:
What we are going to test is to see that after you asked, she will definitely give you at least some answer and not ignore you. Also if her answer is “YES” we would like to see MarriageService called Marry method.
Class which we are going to test is named LearningMocking and has constructor that accepts potential husband/wife and marriageService. Whole story takes place in RestaurantDinner method.
First let’s test that after you asked she gives at least some answer. Since we are not interested in concrete instances we just generate mocks for our interfaces, and passing null instead of marriage service. I’m using RhinoMocks in this example.
This ensured that at least she will give you some answer. In next test we will have some mix and will use concrete class Linda. We have generated Stub for return value of your speech, so instead of
writing concrete class for husband we’ve used stub. This test shows that
she will not marry you:
Let’s use another strategy to ask Linda:
Except of verifying that Marry method was called we also verify that it was called with instance of linda and none else with line Arg<IPotentialWife>.Is.Equal(linda). As well you could setup constructor arguments for MarriageService, since it is not an interface. Also with Rhino.Mocks you will need to have method Marry to be virtual. If it is not virtual and you don’t have interface for it you may need to extend that class with your own.
In the end we’ve got this method:
Please write down if you would like to see more complex mocking examples.