Introduction
Writing unit testing code is really easy.
It's not much more then writing some client code of the library you want to test and add some assert calls to check (test) if the code works as expected. With C# now we have lots of alternatives to do that.
But is it just that?
Not really!
Let's briefly look at some principles behind unit testing.
A unit test, as the name implies, should test just a unit a code. If it doesn't and it ends up depending on some other code then it becomes hard to tell why the test passes or not.
Also, depending on other code makes test hard to make repeatable. Just think about testing a method that depends on some database operation, now you should take care of maintaing database state over repeated calls to your test suite.
Being able to isolate units of code not also makes it more testable but also easier to work with and to refactor.
This post will try to explain some good practices to make your C# code more testable.
Constructors should do nothing
This is an important rule you should enforce if you want your code to be testable. It also makes it easier to enforce SRP (Single Responsibility Principle).
In the class constructor, objects should not be created, because if they are then your class becomes coupled to them and you are not able to inject testing objects during unit testing.
Lets jump to some sample code.
public class StringsCalculator
{
public int Sum(string x, string y)
{
int xi = 0;
int yi = 0;
int result = 0;
if (int.TryParse(x, out xi) && int.TryParse(y, out yi))
{
result = xi + yi;
}
else
{
throw new ArgumentException("Strings passed are not integers.");
}
return result;
}
}
This class StringsCalculator contains a method Sum that takes two strings and tries to sum them if the can be parsed as numbers. It clearly does two things, converting strings to integers and summing them. So if we want to test does separatly we should separate the two responsibilities. Perhaps separating the string conversion in a class StringToNumber:
public class StringToNumber
{
public int Convert(string stringNumber)
{
int result = 0;
if (!int.TryParse(stringNumber, out result))
{
throw new ArgumentException("String is not a number");
}
return result;
}
}
Thus we can refactor our StringsCalculator class:
public class StringsCalculator
{
StringToNumber stringToNumber;
public StringsCalculator()
{
this.stringToNumber = new StringToNumber();
}
public int Sum(string x, string y)
{
return stringToNumber.Convert(x) + stringToNumber.Convert(y);
}
}
This looks better, but what about our test:
[Test]
public void SumStringsNotTestable()
{
StringsCalculator ss = new StringsCalculator();
int result = ss.Sum("2", "3");
Assert.AreEqual(5, result);
}
It tests our class but this way it tests also the StringToNumber class so it's really not "unit" testing.
So let's follow the "Constructors do nothing" rule by doing some refactoring.
First off let's separate the two classes by putting a interface between them. In Visual Studio we just need to right click on the StringToNumber class and choose Refactor->Extract interface... and name it IStringToNumber. Next we need modify the StringsCalculator constructor to accept a parameter of type IStringToNumber.
public class StringsCalculator
{
IStringToNumber stringToNumber;
public StringsCalculator(IStringToNumber stringToNumber)
{
this.stringToNumber = stringToNumber;
}
public int Sum(string x, string y)
{
return stringToNumber.Convert(x) + stringToNumber.Convert(y);
}
}
Mocking objects
Now we can refactor our test to instantiate the StringsCalculator object by passing to its constructor a mock object and not a StringToNumber object. To do this we can use one of the many mocking frameworks for .Net around. I chose the very nice RhinoMocks library, that's easy to use and quite complete. So here's our new test:
[Test]
public void SumStringsTest()
{
MockRepository mocks = new MockRepository();
IStringToNumber stringToNumber = mocks.StrictMock();
StringsCalculator ss = new StringsCalculator(stringToNumber);
Expect.Call(stringToNumber.Convert("2")).Return(2);
Expect.Call(stringToNumber.Convert("3")).Return(3);
mocks.ReplayAll();
int result = ss.Sum("2", "3");
Assert.AreEqual(5, result);
mocks.VerifyAll();
}
As you can see we can instruct the RhinoMocks repository to expect two calls to the IStringToNumber. In this way we are able to verify the inner workings our our class, thus doing what is called white-box testing by calling the VerifyAll() method.
Constructor injection
Having all collaborators classes passed in as constructor parameters enables us to decouple nicely and test in isolation. But what about the client code using this classes, do they have to do lots of code to instantiate all those collaborators? Well there's a nice solution to this, dependency injection containers. In my case I'll use Unity, by using it to instantiate objects, client code doesn't have to prepare alkl those collaborators, Unity will take care of it, even in cascade if those collaborators themselves have other collaborators as constructor parameters. We can implement a integration test to verify our classes together:
[Test]
public void SumStringsUnityTest()
{
UnityContainer container = new UnityContainer();
UnityConfigurationSection section =
(UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(container);
IStringToNumber stringToNumber = container.Resolve();
StringsCalculator ss = new StringsCalculator(stringToNumber);
int result = ss.Sum("2", "3");
Assert.AreEqual(5, result);
}
Unity configuration code could be conveniently located in a helper class.
So, to summarize, we can say: Constructors do nothing, all collaborators are passed in as parameters so we can mock them in unit tests and let a dependency injection mechanism compose them in client code.
For me, changing code to be testable is... detestable!
ReplyDeleteIn fact, you have to define "Unit". What is a unit?
In your case, "Business" unit is to sum two numbers. Everything else is undercover. As we do black box testing, we do not care about anything else.
Why introducing another class and another interface we do not "business" care, but only "testable" care?
Hi Ludovic,
ReplyDeleteThanks for taking time to read my post and to write a comment!
"Unit" in unit testing is a unit of code, not of business rules.
But... in this case you could even argue that the two classes are responsible of two different concerns. One contains the logic behind converting strings to numbers and the second one the logic behind summing the two.
Anyway keep in mind this is just a sample, no one would really write that code for some real application. Like no one would really write a method that outputs "Hello world!" to the user...
Making code testable doesn't necessarily mean you have to refactor, most of the times you can design your classes to work like that from the beginning. Having the testability concern in mind helps writing code that works better. Code that adheres to SOLID principles http://en.wikipedia.org/wiki/Solid_%28object-oriented_design%29 is code that is more testable.
The ideas behind the "Constructors do nothing" rule are well defined in Google guidelines for writing testable code, I strongly suggest to take a look at them at http://misko.hevery.com/code-reviewers-guide/ and to download the PDF file linked there. Very nice indeed!
Yes I know all that stuff.
ReplyDeleteBut, we write code for business needs and not for code needs...
Thus, why not be driven by 'Business' unit testing?
Then if you need to structure your application, for managing complexity, for updatability, readability or any kind of ...ity: that's fine. You structure your code with good practices and then, you need 'code' unit testing too ('business' sub-unit testing? :-)).
Software is becoming more and more a complex thing, users expect more and requirements grow.
ReplyDeleteSo managing complexity is the heart of developing software. Applying the "constructor do nothing rule" seems a big investment, but it's really not and it yields high dividends.
Hi Ludovic, Giorgo.
ReplyDeleteI think it's whether this is subject to test-first development or to some kind of after-the-fact testing to verify some sort of (then black box) functionality. Both of you are right, but you seem to have different scenarios in mind.
When doing test-driven development, then all the post's statements apply - writing testable code IS a business value in itself, not or hardly testable code generally is sloppy code (And anyway: how could you practically develop such code with TDD?).
But if you test after the fact (maybe against a third-party component, or you chose to have a black-box testing strategy for some reason), then 'refactoring' code only to make it testable clearly is a smell, and it even is no possible choice in most cases.
Personally, I always followed the rule 'C'tors must not contain any business logic' intuitively, but it's nice to now see it written down explicitly...
Regards
Thomas
I can see TDD is going to be a regular practice of development. Even for any existing complex system, when it comes to enhancement or modification to support, it becomes a nightmare if there are many complex classes exists which are not testable.
ReplyDeleteI have seem people scared of touching legacy code in the fear of breaking something. I would rather prefer to right testable evidences of any functionality to reduce regular testing overhead to ensure things are working as per expectation.
Now we have many nice frameworks for mocking and unit testing which helps to get these things quickly so why not...
Thanks Sujit Singh for reading my blog and commenting.
ReplyDeleteIn fact the techniques and the tools that are available today make it really easy to do TDD.
And making code testable is not just about testing, it's about making design decision about code that help in encapsulating logic nicely. So the code is not only testable but also maintainable and this means it can grow without collapsing under the weight of big balls of mud...
Java Articles | IT Technical Articles | Dot Net Framework Articles |
ReplyDeleteJavaScript Articles | Java Training Institutes | Single Page Application Development
Dependency Injection by configuration ASP.NET MVC Training ASP.NET MVC Training The pattern is similar to the Service locator pattern as defined by Martin Fowler. ASP.NET MVC Online Training MVC Online Training class implementing ISessionFactory Online MVC Training India Chennai Online MVC Training India
ReplyDeleteTo learn Dot Net Training in Chennai Dot Net Training in Chennai LINQ, you should have through understanding on Func Delegate Dot net Training Institutes in Chennai Dot Net Training Institutes in Chennai . To Know Func Delegates, you should know delegates. .Net Training in Chennai .Net Training in Chennai . To know delegates, you should get trained in Anonymous method and anonymous objects. .net training online India
ReplyDelete
ReplyDeleteEnter Key Office Setup, after purchasing MS Office from visit www.office.com/setup, sign in to your Microsoft account then enter product key for Office Setup
Excellent article. Very interesting to read. I really love to read such a nice article. Thanks! keep rocking.
ReplyDeleteglobal seo packages
Online Marketing Services in bangalore
Seo services in bangalore
Microsoft office setup is the software setup file with this setup file you can install on your computer and some of the supported device to use Microsoft office.
ReplyDeletewww.office.com/setup
office.com/setup
office com setup
ReplyDeleteThanks for the informative article. This is one of the best resources I have found in quite some time. Nicely written and great info. I really cannot thank you enough for sharing.
rpa training in bangalore
best rpa training in bangalore
RPA training in bangalore
rpa course in bangalore
rpa training in chennai
rpa online training
Whoa! I’m enjoying the template/theme of this website. It’s simple, yet effective. A lot of times it’s very hard to get that “perfect balance” between superb usability and visual appeal. I must say you’ve done a very good job with this.
ReplyDeleteAWS TRAINING IN CHENNAI | BEST AWS TRAINING IN CHENNAI
aws training in chennai"> aws training in chennai | Advanced AWS Training in Chennai
AWS Training in Velachery, Chennai | Best AWS Training in Velachery, Chennai
AWS Training in Tambaram | Best AWS Training in Tambaram
ReplyDeleteWhoa! I’m enjoying the template/theme of this website. It’s simple, yet effective. A lot of times it’s very hard to get that “perfect balance” between superb usability and visual appeal. I must say you’ve done a very good job with this.
AWS TRAINING IN BTM LAYOUT | AWS TRAINING IN BANGALORE
AWS Training in Marathahalli | AWS Training in Bangalore
Nice post. Thanks for sharing the valuable information. it’s really helpful. Who want to learn this blog most helpful. Keep sharing on updated posts…
ReplyDeleteData Science course in rajaji nagar
Data Science with Python course in chenni
Data Science course in electronic city
Data Science course in USA
Data science course in pune | Data Science Training institute in Pune
Data science course in bangalore
This is most informative and also this post most user friendly and super navigation to all posts... Thank you so much for giving this information to me..
ReplyDeleteAWS Training in pune
AWS Online Training
AWS Training in Bangalore
This comment has been removed by the author.
ReplyDeletenice explanation, thanks for sharing, it is very informative
ReplyDeletetop 100 machine learning interview questions
top 100 machine learning interview questions and answers
Machine learning interview questions
Machine learning job interview questions
Machine learning interview questions techtutorial
Machine learning job interview questions and answers
Machine learning interview questions and answers online
Machine learning interview questions and answers for freshers
interview question for machine learning
machine learning interview questions and answers
Thank you for this informative blog
ReplyDeleteTop 5 Data science training in chennai
Data science training in chennai
Data science training in velachery
Data science training in OMR
Best Data science training in chennai
Data science training course content
Data science certification in chennai
Data science courses in chennai
Data science training institute in chennai
Data science online course
Data science with python training in chennai
Data science with R training in chennai
thanks for this informative article it is very useful
ReplyDeleteMachine learning taining in chennai
artificial intelligence and machine learning course in chennai
best machine learning training institute
top institutes for machine learning in chennai
machine learning course training institute in chennai
machine learning certification
machine learning training institutes
best institute to learn machine learning in chennai
machine learning course training
machine learning with r training in chennai
Download office setup key from http://wwwofficeoffice.com/setup and activate all office products like Excel, world, power point, outlook etc. Office.com/setup provide latest
ReplyDeleteoffice.com/setup
www.office.com/setup
office.com/setup - Here you can download latest version of Office Setup the link says 2016 but the version is most
ReplyDeleteoffice.com/setup
We are your right choice as we rectify the problem and deliver you effective solutions that will fix your Brother Printer Support instantly. Feel free to call on our toll-free number and get your device issues corrected.
ReplyDeleteMany types of issues facing customers when using AOL Desktop Gold. My AOL Desktop Gold continues breaking the following 5 minutes of opening. I am using it on my PC. My personal computer is an i5 processor with 4 GB RAM. All of this is running fine besides AOL desktop Gold. Any modifications or instructions for fixing my AOL Desktop gold? How to resolve when AOL Desktop Gold when not working properly Reinstall this AOL Desktop Gold software in your device. Once in a while software records ousted suddenly and AOL quits working. It can you resolve an easy way additionally by reinstalling AOL Gold Software.
ReplyDeleteMore Information
Nice blog,I understood the topic very clearly,And want to study more like this.
ReplyDeleteData Scientist Course
I am really enjoying reading your well written articles. It looks like you spend a lot of effort and time on your blog. I have bookmarked it and I am looking forward to reading new articles. Keep up the good work.
ReplyDeletedata science course
Great explanation to given on this post and i read our full content was really amazing,then the this more important in my part of life.
ReplyDeleteThe given information very impressed for me really so nice content.
aws training in chennai | aws training in annanagar | aws training in omr | aws training in porur | aws training in tambaram | aws training in velachery
I'm not one of those readers that comments on articles often, but yours really compelled me. There's a lot of interesting content in this article that is interesting and bold.
ReplyDeleteBest Data Science training in Mumbai
Data Science training in Mumbai
I just got to this amazing site not long ago. I was actually captured with the piece of resources you have got here. Big thumbs up for making such wonderful blog page!
ReplyDeleteSimple Linear Regression
Correlation vs Covariance
Thanks for sharing such an informative post on Unit testing and the "constructors do nothing" rule
ReplyDeleteIf you are looking for high payable IT job, take up
Data Science Course in Chennai
Data Science Training in Chennai
Data Science Certification in Chennai
Data Science Training Institute in Chennai
Data Science Classes in Chennai
Data Science Online Course
Best Online Data Science Courses
Data Science Online Training
best data science certification online
data science certificate online
Read your blog, Excellent informative post on Unit testing and the "constructors do nothing" rule
ReplyDeleteIf you are looking for AWS job with unexpected Pay, then visit below link
AWS Training in Chennai
AWS course in Chennai
AWS Certification in Chennai
AWS Training
Best AWS Training in Chennai
aws online training
aws online course
learn aws online
aws certification online
aws certification training online
ReplyDeleteNice content written on Unit testing and the "constructors do nothing" rule
If you are looking for RPA related job with unexpected Pay, then visit below link
RPA Training in Chennai
RPA Course in Chennai
RPA Training
RPA Course
Robotic Process Automation Training in Chennai
Robotic Process Automation Training
RPA Training Institute in Chennai
RPA Training in Velachery
Robotic Process Automation Certification
This is excellent information. It is amazing and wonderful to visit your site.Thanks for sharing this information,this is useful to me.
ReplyDeleteTeradata Online Training
Teradata Classes Online
Teradata Training Online
Online Teradata Course
Teradata Course Online
Wow it is really wonderful and awesome thus it is very much useful for me to understand many concepts and helped me a lot.
ReplyDeleteCloud Computing Online Training
Cloud Computing Classes Online
Cloud Computing Training Online
Online Cloud Computing Course
Cloud Computing Course Online
After reading your article I was amazed. I know that you explain it very well. And I hope that other readers will also experience how I feel after reading your article.
ReplyDeleteMachine Learning certification Online Training in bangalore
Machine Learning certification courses in bangalore
Machine Learning certification classes in bangalore
Machine Learning certification Online Training institute in bangalore
Machine Learning certification course syllabus
best Machine Learning certification Online Training
Machine Learning certification Online Training centers
Thank you for this informative blog
ReplyDeletepython training in bangalore | python online training
artificial intelligence training in bangalore | artificial intelligence online training
machine learning training in bangalore | machine learning online training
blockchain training in bangalore | blockchain online training
uipath training in bangalore | uipath online training
Very interesting to read this article.I would like to thank you for the efforts you had made for writing this awesome article. This article inspired me to read more. keep it up.
ReplyDeleteCorrelation vs Covariance
Simple linear regression
data science interview questions
Excellent Blog! I would like to thank for the efforts you have made in writing this post. I am hoping the same best work from you in the future as well. I wanted to thank you for this websites! Thanks for sharing. Great websites!
ReplyDeleteSimple Linear Regression
Correlation vs Covariance
It's so great to know you are a writer that cares about the information you provide. This is smartly done and well-written in my opinion.
ReplyDeleteData Science training in Mumbai
Data Science course in Mumbai
SAP training in Mumbai
This is excellent information. It is amazing and wonderful to visit your site.Thanks for sharing this information,this is useful to me.
ReplyDeleteAWS training in Chennai
AWS Online Training in Chennai
AWS training in Bangalore
AWS training in Hyderabad
AWS training in Coimbatore
AWS training
Thanks for giving an excellent Message...Waiting for next article..
ReplyDeleteSpark Training in Chennai
Tableau Certification in Chennai
Appium Training in Chennai
Tableau Training in Bangalore
Good Post! , it was so good to read and useful to improve my knowledge as an updated one, keep blogging.After seeing your article I want to say that also a well-written article with some very good information which is very useful for the readers....thanks for sharing it and do share more posts likethis. https://www.3ritechnologies.com/course/angular-js-training-institute-in-pune/
ReplyDeleteI am looking for and I love to post a comment that "The content of your post is awesome" Great work!
ReplyDeletedata science interview questions
You actually make it look so easy with your performance but I find this matter to be actually something which I think I would never comprehend. It seems too complicated and extremely broad for me. I'm looking forward for your next post, I’ll try to get the hang of it!
ReplyDeletedata science courses
Hello there! This post couldn't be written any better! Reading this post reminds me of my good old room mate! He always kept talking about this. I will forward this page to him. Pretty sure he will have a good read. Many thanks for sharing!
ReplyDelete