Did you know? The GC.KeepAlive() method in the .NET Framework is not used to prevent garbage collection of an object for the entire method scope, as you might think. Instead, it explicitly ensures that the object remains referenced at a specific point in the code after it’s last used. It’s particularly useful when dealing with unmanaged code or resources where the runtime might release an object too early because no managed references exist for it.
Welcome to dotInsights by JetBrains! This newsletter is the home for recent .NET and software development related information.
🌟 Featured Content
This month’s Featured Content is from Daniel Ward. Daniel is a Microsoft .NET MVP and software consultant at Lean TECHniques. He helps teams deliver high-quality software while adopting lean practices such as effective CI/CD, automated testing, and product management. He co-organizes the San Antonio/Austin .NET User Group and also writes a technical blog. Outside of work, he enjoys playing piano and guitar, swing dancing, and game development.
Are your tests actually catching bugs?
Having a strong test suite is an important (and necessary, I would argue) part of creating high quality software that’s adaptable to changes. Once you’ve written those tests, though, how do you know they’re actually catching bugs? “Never trust a test you haven’t seen fail” is a great guideline for writing new tests, but what about after that?
This is where mutation testing comes in. Simply put, mutation testing is a way to test your tests. In my experience, it’s not a very common strategy among developers – including myself! Before I learned about it, I already felt confident in the way I wrote tests, and didn’t want to yet invest the time to learn another testing framework and philosophy. However, once I understood what mutation testing is, and how easy it is to adopt, I became a big supporter of it.
Testing your tests
To see how simple mutation testing really is, try this: go into one of your projects and change a + operator to a – operator and see if the tests around that code still pass. If they do, that means your tests probably aren’t as amazing as they could be. Congratulations, you’ve just done mutation testing!
Of course, manually changing your code over and over like this would be very painful and time consuming, and this is what mutation testing libraries are for. Stryker, one of those libraries, is a popular option for C# and Typescript. Stryker can help you scale this process by automating it, discovering many mutants all at once and then seeing if your tests fail.
Mutation testing concepts
The core concept is simple:
You create “mutants,” which are small changes to your code. The operator change in the example above is an example of a mutant.
Then, you try to “kill” those mutants. You do this by running the tests that hit the changed code.
If your tests fail (which they should, because your code is now doing something fundamentally different), then you’ve killed the mutant! Otherwise, the mutant has survived, and you probably need to update your test cases.
At the end of the run, you’re given a “mutation score” of 0-100%. This is the number of mutants that were killed compared to the total that were found. Just like with code coverage, a higher number is better.
Getting started
One of the great things about getting started with mutation testing is that you don’t necessarily need to enforce it. Rather than fail the build on a low mutation score, your team may decide to just use it as a soft metric to identify weak tests. Or, you may choose to just run Stryker locally. You’ll be able to improve the quality of your tests over time, and your team won’t even know that you’re using Stryker – you’ll just end up with better quality tests as a result! Not only that, but you’ll start to get a feel for what does make a strong test case and hopefully create less mutants in the future. In this way, Stryker can also be a great learning tool for creating high quality tests.
However you choose to use it, mutation testing is a low effort way to get a lot of value out of your test suite, and I encourage you to try it out.If you’d like to have a practical code example and see Stryker in action, I’ve previously written about mutation testing with Stryker in C# at my blog, and also given a talk on it, which can be found on Youtube.
Each month we feature tutorials or tips from our .NET Guide.
Profiling in Rider – Maarten Balliauw
In this tutorial, we will have a look at profiling options in Rider. We will explore profiling modes and their differences, look at Dynamic Program Analysis to do automatic memory profiling. We will then use these to optimize the performance of an existing application, and make it run faster.