C# 9.0 : Record Type Simplifies Unit Testing
Introduction:
Microsoft has released C# 9 with .NET 5.0. It has lots of new features. One feature I am particularly excited about is new Record Type in C# 9. We can now define our data classes with less code, and it looks clean.
It also provides synthesized methods to provide value semantics for equality. Which makes unit test verification lot easier. Without the Record Type, if we use Class to define entity and when a new instance is created in a service under test to pass it to another class’s method, then we need to use It.Is<T>(...)
to provide which field values are equal in these instances or write Mock Verification to verify correct instance of the object was passed as parameter.
In this article I have described how C# 9.0 Record Type simplifies unit testing and mocking the dependencies.
Scenario:
Let’s consider a scenario where we have an API endpoint to create new Person
in PersonsController
. This endpoint takes a NewPersonRequest
as parameter from post body. It then calls InsertPerson
method of PersonService
class.
InsertPerson
method applies some business logic and transforms NewPersonRequest
into Person
database entity and send it to InsertPersonInD
method of PersonRepository
class, to insert it in the database. Repository method returns a Person
with new Id
if it successfully inserts it in the database. It returns null if not able to insert it.
InsertPerson
method transforms Person
in the PersonResponse
and sends back to controller method. Which returns result to client.
We want to write a unit test for PersonService
class's InsertPerson
method.
Note: Make sure Projects are using .NET 5.0 Framework.
Now Let’s Discuss Code:
Persons Controller:
Person Class:
New Person Request Class:
Person Response:
Person Service Interface:
Person Service Implementation
Person Repository Interface
Person Repository Implementation
Person Service Test class
Debug the Test:
Let’s now debug the test. Right click on the test method and select ‘Debug Test’ from the context menu. First break point is on the line where we are adding a mock setup for InsertPersonInDbStore
method. We are setting up these values for newPerson
variable which should be passed as a parameter for this method.
Press F5 key to continue debugging. Next it would throw an exception in the InsertPerson
method of PersonService
class where it calls to InsertPersonInDbStore
. Exception says that the Mock setup can not be found for this method. Although we have done one.
If we hover over the instance then it shows same values for every fields same as the instance created for Mock setup.
So what’s the problem here? It is because the Person
instance was created in Mock and instance created here, does not reference to same memory location and hence .NET does not think they are the same instances.
We can solve this issue by changing Mock setup as below:
This setup will be fine if there are handful of fields, but what if we have 10 or 15 fields and we have to write lots of unit tests, then we have to implement IEquatable<Person>
interface in the Person
class.
Let’s see how Record type solves this issue without any extra work. Change Person
class
to record
as below:
Or we can also declare it in traditional way
Now run the Test again, and this time it passes without any issue.
Summary:
As we can see record type reduces not only coding time and number of lines, but also provides many other benefits. Read more about C# 9.0 features here. Please let me know if you have any thoughts about it in the comments below.
Originally published at https://www.sharpprogrammer.net on January 30, 2021.