Writing your F.I.R.S.T. Unit Tests
Tags: unittests, programming, codequality, testing
Published: 2021-08-27 11:53:43

## What are Unit Tests?
By design, **Unit Tests** are automated tests of _small_ units of code that are tested in an **isolated** fashion. Essentially, an unit test is a program that calls the (`public`) methods of a class and checks if the results are as expected

---

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hfgkf5icaiwuczgiwvb7.png)

## Benefits to Unit Testing
If you wrote your unit tests correctly, there are several benefits they will bring to your maintenance process:
* **Unit Tests will find bugs while you're still developing:** if you are refactoring a section of code, or even including a new one, and your past tests start to _fail_, it means that you changed the behaviour of that method and that might imply on a bug!
* Any correction cost regarding the newly found bugs is considerably **lower** than if they were found while in production
* In other words, Unit Tests protect your code against **Regression**: system changes that create bugs
* After changing your code, you **must** run the test suite! That way you'll find if there was any regression (if any test fails)

---
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vbl8bsv1v70dp35ee2jx.png)

## F.I.R.S.T. Principles
Just as we have our S.O.L.I.D. principles for programming in general, there are a couple of principles for general good practice in unit testing: the **F.I.R.S.T.** principles. Let's go over them.

### [F]ast
The developer **should not** hesitate on running the test suite at any point of the development cycle, even if there are thousands of unit tests. They should run in a matter of seconds. If a test takes too long to run, it probably is doing more than it should — and, therefore, is not an **unit** test!

### [I]ndependent/[I]solated
For any given unit test, it should be **independent** of everything else so that its results are **not** influenced by any other factor. With that definition, they should usually follow the “3 A’s of testing”: **Arrange, Act, Assert** (also known as “Given-When-Then”).
* **Arrange:** All needed data should be provided to the test when you are about to run, and it should **not** depend on your environment.
* **Act:** The actual method you are testing should be run.
* **Assert:** Unit Tests should only test **one** outcome, meaning each test should assert that **one** state of an object should be tested. Note that this does not mean that you should only check **one** variable of a class response, but that **all** variables tested should be related to the method you ran

### [R]epeatable
Tests should be repeatable and deterministic: every single time you run a test their values **cannot** change, no matter the environment.

### [S]elf-Validating
The test itself should tell you if it passed. There should not be any need of manually checking the values. Most assertion libraries (such as `Shouldly`) work in favour of that principle.

### [T]horough
Your test should cover all _“happy paths”_ of a method (`xUnit` makes that possible with `Theory` tests), all edge cases (where you think the test might fail), illegal arguments, security flaws, large values… in sum, every possible use case scenario should be tested, not only enough to have (near) 100% Code Coverage

### The extra T: Timely
Following [TDD](https://en.wikipedia.org/wiki/Test-driven_development), Unit Tests should be written before the production code that will be tested. This can be done by writing the abstraction (Interface) and then the test based on the method signature and spec alone. After the test is written, your code can be produced and tested.

---
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b54ir52c6zm8rsf98zcc.png)

## A few tools 
For `C#`/`.NET` development, a few tools/frameworks are available by default, and a lot more available as **NuGet packages**. Here are some **highly recommended** options
* Base Framework: [`xUnit`](https://github.com/xunit/xunit) is a powerful and complete testing framework for .NET that is usually bundled with **VisualStudio** alongside `NUnit`. Overall both are good frameworks, but `xUnit` is more readable and intuitive
* Assertion Tool: [`Shouldly`](https://github.com/shouldly/shouldly) is a much more intuitive way of asserting your test results than the native Assert class. The github repo gives plenty of examples but just one very simple sample should be enough to show how readable and simple `Shouldly` is:
```cs
// using Assert
Assert.IsTrue(booleanVariable);
// using Shouldly
booleanVariable.ShouldBeTrue();
```
* Mocking Tool: [`NSubstitute`](https://github.com/nsubstitute/NSubstitute) is a powerful tool that allows you to create mocks for any given class or interface so that you can easily test any method that would, in a regular case, use external environment such as 3rd Party APIs or DataBases. It has a simple learning curve and is [well documented](https://nsubstitute.github.io)

---
## References
This article is a compilation made from different source materials cited below:
* General “Software Maintenance and Evolution” and “Software Testing” theory
* https://dzone.com/articles/writing-your-first-unit-tests
* https://github.com/ghsukumar/SFDC_Best_Practices/wiki/F.I.R.S.T-Principles-of-Unit-Testing
* https://medium.com/@tasdikrahman/f-i-r-s-t-principles-of-testing-1a497acda8d6