Ok…so how do you handle this? I’m sure most of us out there in the world have other projects in flight and don’t want to end up accidently pulling in this problematic NuGet package. Most clients/project managers/projects don’t respond well to having to stop active development on a dime just to refactor a bunch of test code. So what do we do? Microsoft has us covered in this scenario. In this case we only want to allow Moq v4.18.4. We will come back later on when we have time to refactor/replace Moq. Let’s consult the docs shall we?
We need to go through our solution and replace each PackageReference for Moq in each project that uses it. So we’re going from this:
If you’ve been paying attention to LinkedIn, you’ve probably noticed that I am looking for a new job. If you are hiring and you would like to talk, shoot me an email.
When I get this new job and I have some income, I’m going to update my licenses for the following Linqpad and NCrunch.
I love this app. I first used this back during my tenure at Logica when we were working with StreamInsight. It’s a good app to use to be able to quickly test out chunks of C#, VB.NET, and F# code. The app is extensible so you can download other drivers that let you hook up to other SQL/NoSQL databases. Really cool for learning/prototyping code. Check out the website for more information: https://www.linqpad.net.
NCrunch is an automated concurrent testing for Visual Studio. What that means in English is that you can configure it to run your unit tests as you are typing your code. You can configure it to run the unit tests that are impacted by the changes you make so you aren’t running the entire suite of unit tests. This is very handy, especially if you have good code coverage. It even collects code coverage numbers and performance metrics. More information can be found on the website: https://www.ncrunch.net.
I have a job change coming up and I thought it would be a good idea to do an update to New High Score (update)! and New High Score! posts. Since those 2 posts I’ve had a couple work items that required updates to that monster class. Here is what the metrics look like now.
Depth of Inheritance
Lines of Source Code
Code metrics covering the class in aggregate.
Depth of Inheritance
Lines of Source Code
Code metrics covering the 3 longest methods in the class.
I’m a big believer in leaving a code base better than you found it. I had a couple work items that required me to go in and refactor this monster class a bit. As a developer I feel a lot more comfortable making these kinds of changes (i.e. Strangler Fig design pattern) when I have the proper tools such as JetBrains ReSharper. The payoff for this change was that it allowed me to write unit tests to cover the part of the class that I needed to complete the work items. When you have a code base that is this convoluted, it’s nice to have a series of unit tests to proof that the changes you made to the code base work. This came in handy in a discussion with a QA guy. I was able to walk him through each one of the tests I had written. Turns out the issue was in a basic understanding of the work item the way it was written. However, my code worked correctly in the end and I could prove it.
I wasn’t the only one working on this code. There were at least 2 or 3 teams making changes to this code.
The purpose behind unit testing is to help ensure the code you have written performs as expected. The running of unit tests can be more effective when it is automated on a developers machine and as part of your CI/CD pipeline. Automated unit tests can also take the load off of limited QA resources by letting them focus on higher level testing (i.e. integration testing, regression testing, and acceptance testing).
Nowadays, when I’m handed a new code base to work on, I treat it as suspect. I have no idea if the code base will even run. If it does run, how do I know that it runs correctly? Unit tests will help me determine what shape the code base is in.
In general, I follow the red-green-refactor approach when writing unit tests. I write my tests in this order typically:
Cover the happy paths through the code you are testing.
Cover the upper and lower ends of inputs to your code.
Cover any know edge cases known at the time.
As a follow on to this process, if and when bugs are reported against code that I’m maintaining, I can then write a unit test to reproduce the bug and it will also tell me when it is fixed satisfactorily.
What unit testing framework do you like the best and why?
xUnit.net hands down. xUnit.net requires fewer attributes to set your tests up (i.e. Fact and Theory). Another feature I think is neat is using a class’s constructor (w/o any attributes) as a setup method for your unit tests. This is great because it follows the way classes work naturally.
What other unit testing frameworks have you used?
I have used NUnit and Visual Studio Unit Testing Framework (aka MSTest). I prefer NUnit to MSTest though.
What is the right amount of code coverage?
If I have to give a number, I would say between 70% and 80%. I would have a higher number for code that is heavily used and relied upon by other parts of the solution.
How would you go about writing unit tests?
I like using TDD on more complicated/intricate code because it let’s you work your way through the code step by step. I prefer a Given-When-Then (GWT) approach over Arrange-Act-Assert (AAA). The GWT approach allows you to write more human-readable unit tests. The AAA approach works, but is not as easily readable. In general, writing clear and understandable code is the goal. Here are a couple links that talk about GWT vs AAA:
Testing the wrong thing – Software development teams need to make sure they are writing unit tests to cover code that they have written.
Getting lost in setup hell – This occurs when the setup for your unit tests starts to become tedious and takes a lot of time to get right. Using a GWT style seems to help with this.
“I’ll just comment out this unit test to get things working so I can check in my changes.” – I think this is just developers being lazy and apathetic about the changes being made to the solution. It is not a behavior I would encourage on my software development team.
So that’s my current philosophy on unit testing. What do you think? Am I wrong? Did I miss something? Feel free to post a comment or send me an email.