Reader small image

You're reading from  Refactoring with C#

Product typeBook
Published inNov 2023
Reading LevelIntermediate
PublisherPackt
ISBN-139781835089989
Edition1st Edition
Languages
Right arrow
Author (1)
Matt Eland
Matt Eland
author image
Matt Eland

Matt Eland is a Microsoft MVP in Artificial Intelligence (AI) who has been working with .NET since 2001. Matt has served as a senior engineer, software engineering manager, and .NET programming instructor. He is currently an AI specialist and senior consultant at Leading EDJE near Columbus, Ohio, where he helps companies with their software engineering and data science needs using C# and related technologies. Matt speaks and writes in his community and co-organizes the Central Ohio .NET Developers Group while pursuing a master's degree in data analytics.
Read more about Matt Eland

Right arrow

Advanced Unit Testing

As we’ve seen, testing is incredible and can give you the freedom to effectively refactor your code in relative safety. Sometimes, code is written in a way that makes testing difficult and you need a few more tools. In this chapter, we’ll explore a handful of popular .NET libraries that can improve the readability of your tests and give you more options for testing code – including those tricky classes with complex data or dependencies.

We’ll cover the following topics in this chapter:

  • Creating readable tests with Shouldly
  • Generating test data with Bogus
  • Mocking dependencies with Moq and NSubstitute
  • Pinning tests with Snapper
  • Experimenting with Scientist .NET

Technical requirements

The code for this chapter is available from GitHub at https://github.com/PacktPublishing/Refactoring-with-CSharp in the Chapter09 folder.

Libraries change with new releases and some of these changes may cause issues with code in this chapter. Because of this, here are the exact names and versions of the libraries that are used in this chapter at the time of writing:

  • Bogus 34.0.2
  • FluentAssertions 6.11.0
  • Moq 4.20.2
  • NSubstitute 5.0.0
  • Scientist 2.0.0
  • Shouldly 4.2.1
  • Snapper 2.4.0

Creating readable tests with Shouldly

In Chapter 6, we saw how the Assert class is used to verify the behavior of existing classes through code such as the following:

Assert.Equal(35, passengerCount);

This code verifies that passengerCount is equal to 35 and fails the test if it is a different number.

Unfortunately, this code has two problems:

  • Assert methods take in the expected value first and the actual value second. This is different than how most people think about things and can lead to confusing test failure messages, as we saw in Chapter 6.
  • The code doesn’t read incredibly well in English, which can slow you down as you are reading tests.

Several open-source libraries address this issue by providing an alternative syntax for writing assertions in unit tests through sets of extension methods they introduce.

The most popular of these libraries are FluentAssertions and Shouldly. While FluentAssertions is by far the more popular library, I find...

Generating test data with Bogus

In Chapter 6, I mentioned that tests are a form of documentation that explains how your system should work.

Keeping that in mind, look at the following test, which tests the interaction of the Passenger and BoardingProcessor classes:

[Fact]
public void BoardingMessageShouldBeAccurate() {
  // Arrange
  Passenger passenger = new() {
    BoardingGroup = 7,
    FirstName = "Dot",
    LastName = "Nette",
    MailingCity = "Columbus",
    MailingStateOrProvince = "Ohio",
    MailingCountry = "United States",
    MailingPostalCode = "43081",
    Email = "noreply@packt.com",
    RewardsId = "CSA88121",
    RewardMiles = 360,
    IsMilitary...

Mocking dependencies with Moq and NSubstitute

So far, we’ve looked at a few libraries that improve the readability of your tests. In this section, we’ll look at mocking frameworks and see how libraries can help you more effectively test your code.

Understanding the need for mocking libraries

Let’s discuss why mocking frameworks are necessary by revisiting the FlightBookingManager example we introduced in the previous chapter while discussing dependency injection:

public class FlightBookingManager {
  private readonly IEmailClient _email;
  public FlightBookingManager(IEmailClient email) {
    _email = email;
  }
  public bool BookFlight(Passenger passenger,
    FlightInfo flight, string seat) {
    if (!flight.IsSeatAvailable(seat)) {
      return false;
    }
    flight.AssignSeat(passenger...

Pinning tests with Snapper

Let’s say you’ve inherited some complex legacy code that returns an object with a lot of properties. Some of these properties may, in turn, contain other complex objects with their own nest of properties. You’re just starting to work with this code and need to make a change, but there aren’t any tests in place and you’re not even sure what properties are important to verify.

I’ve seen this scenario a few times now and can attest that a special testing library called Snapper is a fantastic solution to this problem.

What Snapper does is it creates a snapshot of an object and stores it to disk in a JSON file. When Snapper next runs, it generates another snapshot and then compares it to the snapshot it stored previously. If the snapshots differ at all, Snapper will fail the test and alert you to that problem.

Snapper and Jest

For those of you with a JavaScript background, Snapper was inspired by the snapshot...

Experimenting with Scientist .NET

Scientist .NET is a library built by GitHub for scientifically refactoring the critical parts of your application.

Let’s say you have a portion of your application that is vital to what the business does but has a significant amount of technical debt. You want to refactor it, but you’re afraid of breaking anything and your existing tests are not sufficient to address those fears, but you’re not sure what tests you need to add. In your estimation, the only thing that will let you feel good about your new code is to see how it does in production.

This is what Scientist .NET helps with. Scientist .NET lets you deploy your new code alongside the legacy code it hopes to replace and compares the results of the two pieces of code. Alternatively, Scientist .NET can be used in unit tests to verify that the old version of a component and the new version of the component achieves the same results.

This concept will hopefully be a...

Summary

In this chapter, we saw several different open-source libraries that can improve the readability and capabilities of your tests.

  • Shouldly and FluentAssertions give you the readable syntax for writing assertions.
  • Bogus allows you to generate randomized test data for values that don’t matter.
  • Moq and NSubstitute help you isolate dependencies and provide alternative implementations for testing.
  • Snapper and Scientist .NET help catch issues where complex objects change in subtle ways.

Not every project will benefit from each of these libraries. However, knowing the tools at your disposal will help you as you refactor and maintain your code and expand your tests.

While it’s possible to do all the things in this chapter without using these libraries, all of these libraries represent established community projects dedicated to solving specific technical concerns.

In the next chapter, we’ll close out this section of this book with...

Questions

  1. What areas of your test code could be more readable? Are there any libraries in this chapter that might help?
  2. How do mocking libraries such as Moq and NSubstitute help in testing?
  3. Do you see any areas of your code where the complexity is high enough that Snapper or Scientist .NET might be able to help?

Further reading

You can find more information about the libraries discussed in this chapter at these URLs:

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Refactoring with C#
Published in: Nov 2023Publisher: PacktISBN-13: 9781835089989
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Matt Eland

Matt Eland is a Microsoft MVP in Artificial Intelligence (AI) who has been working with .NET since 2001. Matt has served as a senior engineer, software engineering manager, and .NET programming instructor. He is currently an AI specialist and senior consultant at Leading EDJE near Columbus, Ohio, where he helps companies with their software engineering and data science needs using C# and related technologies. Matt speaks and writes in his community and co-organizes the Central Ohio .NET Developers Group while pursuing a master's degree in data analytics.
Read more about Matt Eland