csharp wallpaper

Test Driven Development (TDD) helps you to validate our code but something you need to check some result as json and it is not easy to find an easy way. After a couple of post on Stackoverflow, here I want to show my solution. Here some examples of TDD.

For my company I’m creating an Azure Functions with .NET Core 3.x to generate the invoices. I have to consider different scenarios and I want to create a test for that.

Scenario

I thought to create a function where I pass a list of lines for the invoice. In this function I have to check if there is any refund for the user. If so, I have to deduct the amount from the current invoice. If some money to refund are left, I have to create a new refund invoice.

public class InvoiceGeneratorResponse
{
    public List<InvoiceGeneratorDetailResponse> Details { get; set; }
    public List<InvoiceGeneratorErrorResponse> Errors { get; set; }
    public List<InvoiceGeneratorNextInvoiceResponse> NextInvoice { get; set; }
}

InvoiceGeneratorResponse is the result of my class where Details is the invoice list, Errors is the list of incomplete invoices and NextInvoice is the list of refund invoices I have to create.

Now, I want to create a bunch of tests to check every scenario. For that, I have to pass the list of rows to this function and check the result.

So, I was thinking to read the list of rows from a json file and convert it in a list to pass into the function. For the result I want to read another file, convert it in a list and compare the list from the file with the result from the function.

My implementation

In my solution, I created a new test project with NUnit test framework.

Visual Studio - Add new project - Test project
Visual Studio – Add new project – Test our code with json

After that, I want to test my code reading data from json files and check the result of a function with json. For that, I think I have to create a generic class in T to convert the json in a specific model. Pretty easy.

using Newtonsoft.Json;
using System.IO;

namespace PSC.Tests.Code
{
    /// <summary>
    /// Class FileService.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class FileService<T> where T : class
    {
        /// <summary>
        /// Gets the data.
        /// </summary>
        /// <param name="filename">The filename.</param>
        /// <returns>T.</returns>
        public T GetData(string filename)
        {
            var datasetJson = File.ReadAllText(filename);
            var dataset = JsonConvert.DeserializeObject<T>(datasetJson);
            return dataset;
        }
    }
}

Compare json

First of all, I want to understand how to check the result of a function. Each function returns an object (model) and I want to compare this object with the result I expected.

To do this, I thought the easy way was to compare the result as a json with an object that I read from a file. So, I can test our code with json.

With FileService I read a json file and convert it in an object. I’m using the same function to read the input for a function.

But how to compare two jsons? I tried to create a new annotation for my test link in this post but I found quite difficult to change the logic with a complex object like a list of invoices. Also, I considered to use Microsoft Test because it is easy to pass some values as DataAnnotation. The problem with MSTest is that it is impossible to pass a complex object.

Then, standard approach. Code. The problem remains: how test our code with json? How to compare two jsons?

To easy solution I found is called FluentAssertions.Json. With this Nuget package, it is easy to compare to jsons and, in case of errors, having a nice idea where the errors is.

Test our code with json – FluentAssertions.Json

Now, my simple class to test my GenerateAndSaveInvoices function. In my project I created a folder called Data where I save all json files.

using FluentAssertions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

namespace PSC.Tests
{
    public class MonthPaymentTests
    {
        private InvoiceMonthlyService _service;

        [SetUp]
        public void Setup()
        {
            _service = new InvoiceMonthlyService(null, null, null, null, null);
        }

        [Test]
        public void Check_Result_With_One_Organization_Simple()
        {
            List<Organisation> invoice = new FileService<List<Organisation>>().GetData("Data\\invoice-in-1.json");
            InvoiceGeneratorResponse expected = new FileService<InvoiceGeneratorResponse>().GetData("Data\\invoice-out-1.json");

            InvoiceGeneratorResponse response = _service.GenerateAndSaveInvoices(invoice.AsQueryable(), 3, Convert.ToDecimal(0.2), false);

            JToken jExpected = JToken.Parse(JsonConvert.SerializeObject(expected));
            JToken jResponse = JToken.Parse(JsonConvert.SerializeObject(response));

            jResponse.Should().BeEquivalentTo(jExpected);

            Assert.AreEqual(expected.NumberOfErrors, response.NumberOfErrors);
            Assert.AreEqual(expected.NumberOfInvoices, response.NumberOfInvoices);
            Assert.AreEqual(expected.NumberOfOrganisations, response.NumberOfOrganisations);

            Assert.AreEqual(expected.Total, response.Total);
            Assert.AreEqual(expected.TotalAmount, response.TotalAmount);
            Assert.AreEqual(expected.TotalTaxes, response.TotalTaxes);
        }
}

The magic is in the line 29-32. Basically, the test reads 2 json files, one for the input and another for the output to compare. Then it calls the function to test and I pass the list of values from the first file.

Now, I have to create a JToken and for that I serialize the object and parse it. So, I can use FluentAssertions to check the difference in the json objects.

Happy coding!

By Enrico

My greatest passion is technology. I am interested in multiple fields and I have a lot of experience in software design and development. I started professional development when I was 6 years. Today I am a strong full-stack .NET developer (C#, Xamarin, Azure)

This site uses Akismet to reduce spam. Learn how your comment data is processed.