How to unit test private methods in .NET Core applications? (even if it’s bad)

Introduction

Yes it’s bad and dirty!

Since your private methods are only an implementation detail whose existence and behavior is only justified by their use in public methods, then these private methods are automatically tested through public method tests.

In other words, once your public methods are tested, your private methods should be fully covered. If this is not the case, it is either that you have forgotten tests or that your private method does things that are of no use to meet the needs of your public methods. In this case, it is probably necessary to clean them.

“Yes, but my private methods are big and complicated, tests would be very practical Sometimes, we see private methods that are full of stuff or things so complicated, that having tests would still be very practical.”

That is true. We see some.

Even myself I have been I was confronted with this kind of problem:

“Sometimes a bug is located in a private method and I do not want to recreate all the context necessary to call the public method.”

That’s why I’m going to show you how to test them, but do not forget that this should be truly exceptional.

How to?

This is really more simple than you think! we will just use Reflection.

In this example, I will use XUnit and FluentAssertion.

Let’s define a class with a private method:

namespace XUnitAndFluentAssertionDemo
{
   public class Hello
   {
      private string _firstName { get; set; }
      private string _lastName { get; set; }

      public Hello(string firstName, string lastName)
      {
         _firstName = firstName;
         _lastName = lastName;
      }

      public string HelloMan()
      {
        if (string.IsNullOrEmpty(_firstName))
        throw new MissingFirstNameException();

        return this.HelloMan(_firstName, _lastName);
      }

      private string HelloMan(string firstName, string lastName)
      {
         return $"Hello {firstName} {lastName} !";
      }

   }

   public class MissingFirstNameException: Exception
   {
      public MissingFirstNameException(): base("FirstName is missing")
      {
      }
   }
}

Now let’s write the unit test using Reflection:

We will use the well known function Activator.CreateInstance and fetch its methods and properties using Linq, then invoke the method to test with the well known method Invoke:

namespace UnitTests
{
   public class HelloTests
   {
      [Fact]
       public void PrivateHelloManShouldBeWellFormated()
       {
          // Arrange
          var firstName = "John";
          var lastName = "Doe";

          Type type = typeof(Hello);
          var hello = Activator.CreateInstance(type, firstName, lastName);
          MethodInfo method = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
          .Where(x => x.Name == "HelloMan" && x.IsPrivate)
          .First();

          //Act
          var helloMan = (string)method.Invoke(hello, new object [] {firstName, lastName});

         //Assert
         helloMan
         .Should()
         .StartWith("Hello")
         .And
         .EndWith("!")
         .And
         .Contain("John")
         .And
         .Contain("Doe");
       }
    }
}

Conclusion

Wondering “how to test a private method” should raise an alarm.

You should first find a solution to avoid this, review your code, but often it’s not easy because you maintain very old legacy code or your colleagues are stubborn :).

Anyway, I hope this article would help you.

Good luck 🙂

Code reliability: Unit testing with XUnit and FluentAssertions in .NET Core 2 apps

Introduction

I decided to write this article because I’m really fan of XUnit and FluentAssertions expecially for its great syntax.

Xunit

xUnit.net is a free, open source, community-focused unit testing tool for the .NET Framework. Written by the original inventor of NUnit v2, xUnit.net is the latest technology for unit testing C#, F#, VB.NET and other .NET languages. xUnit.net works with ReSharper, CodeRush, TestDriven.NET and Xamarin. It is part of the .NET Foundation, and operates under their code of conduct. It is licensed under Apache 2 (an OSI approved license).

FluentAssertions

FluentAssertions is the best assertion framework in the .NET realm.

FluentAssertions supports the following .NET versions:

  • .NET 4.0, 4.5 and 4.6
  • CoreCLR, .NET Native, and Universal Windows Platform
  • Windows Store Apps for Windows 8.1
  • Silverlight 5
  • Windows Phone 8.1
  • Windows Phone Silverlight 8.0 and 8.1
  • Portable Class Libraries

Fluent Assertions supports the following unit test frameworks:

 

Setup your .NET Core 2 project

Install XUnit

Download it via Nuget package manager:

Or type this command in Nuget package manager console:

PM> Install-Package xunit -Version 2.3.1

Install XUnit Visual Studio runner

This package allow to Visual Studio to discover XUnit unit tests, if you don’t install it, Visual Studio won’t detect them.

Download it via Nuget package manager:

Or type this command in Nuget package manager console:

PM> Install-Package xunit.runner.console -Version 2.3.1

Install FluentAssertions

Download it via Nuget package manager:

Or type this command in Nuget package manager console:

PM> Install-Package FluentAssertions -Version 5.0.0-rc0002

 

Write your unit tests

Example of a class to unit test:

public class Hello
{
   private string _firstName { get; set; }
   private string _lastName { get; set; }

   public Hello(string firstName, string lastName)
   {
      _firstName = firstName;
      _lastName = lastName;
   }

   public string HelloMan()
   {
      if (string.IsNullOrEmpty(_firstName))
         throw new MissingFirstNameException();

       return $"Hello {_firstName} {_lastName} !";
   }

   public string Your()
   {
      return $"Hello {_firstName} {_lastName} !";
   }
}

public class MissingFirstNameException: Exception
{
   public MissingFirstNameException(): base("FirstName is missing")
   {
   }
}

Example of a related Unit tests class:

public class HelloTests
{
   [Fact]
   public void HelloManShouldBeWellFormated()
   {
      // Arrange
      var hello = new Hello("John", "Doe");

     //Act
     var helloMan = hello.HelloMan();

     //Assert
     helloMan
     .Should()
     .StartWith("Hello")
     .And
     .EndWith("!")
     .And
     .Contain("John")
     .And
     .Contain("Doe");
   }

   [Fact]
   public void HelloManShouldBeRaiseExceptionWhenFirstNameIsNotSet()
   {
      // Arrange
      var hello = new Hello("", "Doe");

      //Act
      Action actionHelloMan = () => hello.HelloMan();

      //Assert
      actionHelloMan
      .Should()
      .Throw<MissingFirstNameException>()
      .WithMessage("FirstName is missing");
   }
}

 

Now just run your test with “Test” menu in Visual Studio:

 

That’s it!

Cute unit testing isn’t it? 😉