C# Unit Testing. Why bother?

We use a lot of unit tests in the development process of Docotic.Pdf. Currently, we have 14,820 unit tests. These tests help us stay sure our software works as expected even when we change the software.

Unit test C# and VB.NET code

Sometimes our existing or prospective customers ask us to add a new feature or fix a bug. If the change does not involve a lot of coding, we can implement the change and release an updated version of the library in a few hours. And we are very confident that the new version does not introduce any regressions because we run our tests before the release. This makes our pre-release builds safe for using in a production environment.

Our C# unit tests help us a lot. We believe that unit testing is a crucial practice in software development. That is why I am going to talk more about the significance of unit testing and its benefits.

What good can C# unit tests do

Unit tests execute quickly and can be run at the press of a button. They don't require extensive knowledge of the entire system, which makes them efficient for validating changes. Without unit tests, you would need to perform manual steps to validate expected behavior, which can be time-consuming and error-prone.

Changes to code can introduce unintended issues called regression defects. When using unit tests, you can rerun the entire test suite after every build or code change. This helps catch defects early, reducing the cost of fixing them later. Well-written unit tests act as a safety net during code changes or refactoring.

Tightly coupled code is challenging to unit test. That is why writing unit tests naturally decouples code, making it more modular and maintainable.

Unit tests can serve as documentation of the code. They can clarify how a method behaves for specific inputs (e.g., blank strings or null values) and explain the expected output.

Shared test suites provide a common understanding of the code. Collaboration among team members improves because of clear expectations.

Tools for unit testing in C#

To develop tests, you would need a testing framework. The three major C# testing frameworks for unit testing are MSTest, NUnit, and xUnit. Which one to choose depends on your requirements and taste.

MSTest is the default testing framework provided by Microsoft Visual Studio. You do not need to install anything else to develop and run tests. MSTest offers tight integration with Visual Studio.

xUnit is a modern, extensible testing framework known for simplicity and ease of use. Some say that it helps writing cleaner tests. xUnit also provides the best isolation of tests. Some popular large projects use xUnit for automated testing. ASP.NET Core is one of such projects.

NUnit is a well-established testing framework with a rich feature set and an extensive plugin ecosystem. It might be slower than the other two frameworks and you would need the NUnit 3 Test Adapter to run NUnit 3 tests inside Visual Studio or on the command line.

We use NUnit for Docotic.Pdf tests. One of the main reasons is that we started developing tests for our C# PDF library many years ago when other alternatives were worse or didn't exist. If we were starting today, we might have read the great NUnit vs. XUnit vs. MSTest article and made another choice.

What makes a good C# unit test?

Tests should run fast. Speed matters, because in a mature project, there are thousands of unit tests. Making each test as fast as possible reduces the total time required to run all the tests. This maintains developer productivity.

Each unit test should focus on a specific piece of functionality. Focused tests are not only shorter but also easier to understand and maintain. Developers can grasp the purpose of focused tests faster. To make it even more convenient, don't forget to provide tests with names that are short but give basic information about the purpose of the test. Tests should contain clear assertions.

Unit tests should produce consistent results regardless of the environment. No matter when or where you run the test, it should always provide the same result. To avoid non-deterministic behavior in tests, you better not rely on external data or time. For example, you better not make a test depend on some data downloaded from an URL.

Use mocks and/or stubs to isolate the unit under test from external dependencies. Mocks and stubs are tools used in C Sharp unit testing and in other languages, too. A mock is a fake implementation of a method or object. This fake implementation is used to simulate the method of object behavior in a test. A stub is a dummy implementation of a method or object that is used as a placeholder in a test.

Conclusion

Unit testing C# code isn't just a best practice; it's a necessity. By investing time in writing robust unit tests and creating comprehensive test suites, developers can prevent regressions, improve code quality, and ensure long-term maintainability. So, let's embrace unit testing and build more reliable software.

Contact us if you have questions about unit testing in C Sharp or VB.NET. Questions about C# regression testing are welcome too.

Happy testing! 🧪🔍