How to unit test Internal classes in .NET Core applications?

Introduction

The creation of unit tests is an important step in ensuring the quality of a project. In general, most public methods are tested, but what if you want to test a non-public part of the project?

Putting all classes of your .Net project in public is not recommended. From the moment when you reference your assembly in a project in Visual Studio, you will have access to all your classes, methods, properties and fields marked as public, and there are surely parts of your code that it is not worth better not leave accessible because they could change the behavior of the assembly or have any negative impact. This is why the keywords “internal” and “private” exist. Only then, your non-public types and members can not be called directly from your unit tests because (in principle) your tests are in separate assemblies.

Fortunately, there is a solution for testing non-public types and members, specifically, internal.

In this article I will show you how to achieve our goals.

We will use an attribute, InternalsVisibleTo, which will make it possible to specify that a particular assembly will have access to the types and members marked as being internal of the current assembly.

Solution

Let’s define an internal class to test like this named “Hello

Then let’s try to test it in a Unit testing project:

As you can see, it doesn’t work the “UnitTest” project can’t see the internal class

Now let’s add [assembly: InternalsVisibleTo(“UnitTests”)] as decorator on the namespace, it should solve our problem now 🙂

 

Beautiful isn’t it? 😉

WallabyJs, a smart unit tests runner!

Wallaby.js is a smart runner JavaScript tests and it’s super fast, it runs continuously your tests.

It reports the results directly into your code editor immediately when you change your code, we take example by Visual Studio 2.1 and the Jasmine framework for testing.

Step 1: Install WallabyJs

In our case, we’ll use Visual Studio 2013 to download the addon for Visual Studio WallabyJs here.

Caution : must have at least 4 update for Visual Studio 2013 to be compatible.

Step 2: Configuring WallabyJs

To set the execution environment of WallabyJs, configure three things:

– The path to the JavaScript files functions you want to test

– The path to the Javascript test files

– Javascript framework you want to use (WallabyJs supports Jasmine, Mocha, QUnit)

To do so we must create a json file to the root of your web project, I recommend naming like this: wallaby-jasmine.json, this will visually easily identify our configuration file :

{ 
   "files": [ "Scripts/*.js" ], 
   "tests": [ "Scripts/tests/*.spec.js" ], 
   "testFramework": "jasmine@2.1.3" 
}

The properties “files” and “tests” are arrays, you can put as many files as you want to test, “files” for files containing the test, “tests” for files of unit tests to execute.

You can also select with * all files in a directory you want.

Finally, the framework used in the latest WallabyJs Jasmine is version 2.1.3, you can check here syntax Jasmine.js 2.1 here: http://jasmine.github.io/2.1/introduction.html

Note: With the Framework Jasmine, the name of test file must end with .spec.js

Overview of web project:

Conversion.js (library to be tested)

var Conversion = { 
   livreVersKilo: function (livres) { 
      if (isNaN(livres)) { 
         throw "ValeurLivreIncorrecte"; 
      } 
      return livres / 2.2; 
   } 
};

conversion.spec.js (fichier de tests)

/// <reference path="../conversion.js" /> 
// Specs 
describe("The conversion library", function () { 
   describe("Pound to kilogram conversion", function () { 
      it("Should multiply the number of pounds per 2.2", function () { 
         expect(Conversion.livreVersKilo(22)).toBe(10); 
      }); 
      it("Should not multiply the number of pounds per 2.2", function () { 
         expect(Conversion.livreVersKilo(22)).not.toBe(9); 
      }); 
      it("Should throw an exception if the input is not numeric", function () { 
         var foo = function () { 
            Conversion.livreVersKilo("abc"); 
         }; 
         expect(foo).toThrow("ValeurLivreIncorrecte"); 
      }); 
      it("Should throw an exception if the input is not numeric", function () { 
         var foo = function () { 
            Conversion.livreVersKilo("1"); 
         }; 
         expect(foo).toThrow("ValeurLivreIncorrecte"); 
      }); 
   }); 
});

cap9

Step 3: Start Wallaby Js
To do this, stand on the wallaby-jasmine.json file, right-click and do “Start WallabyJs” :

cap2

If the boot fails, you will be notified in this case to verify the information your configuration file, otherwise if successful the following message:

cap3

From the start, WallabyJs will execute unit tests, the files tests will show green or red square (+ red message on failure) based on the test results:

cap6

Step 4: Add, edit tests

Once you edit your files from unit tests, WallabyJs will restart the tests without any action from you, same as you change your Javascript functions to be tested, WallabyJs will detect this and will also run unit tests.

To see a demo of WalabyJs in action watch the video here

Bonus for those with ReSharper :

Happy owners of ReSharper will be able to enjoy an additional feature:

Indeed other icons will appear in your test files, much like NCrunch, it is possible to launch the unit test in windowed mode :

cap7

cap8

So, what do you think? 🙂

Important detail : it’s not free unfortunately!

For the price, it’s here.

Understanding the Difference Between Unit Test and Integration Test

This article is not intended to exhaustively describe unit tests, but rather to promote a clear understanding of their purpose, and serve as a warning to developers who often confuse unit testing and integration testing (that includes myself, when I was starting out).

What is a Unit Test ?

unit test must be truly unitary. To achieve this :

  • The class must be tested in complete isolation from the SUT (System Under Test)
  •  to ensure that only the class and its methods are being tested.

  • Isolate the dependencies of the tested class by using the “Dependency injection”
  •   pattern.

  • Use a mocking framework to inject dependencies in the form of caps.

Since unit tests should run as fast as possible in order to provide an almost immediate return, they must be banned from accessing files, databases or external services. Tests that talk to a database are not unit tests; they are integration tests.

Unit Test Example

As an example of a unit test where the class is isolated from the SUT, we will use the “Rhino.Mocks” mocking framework. A good article on its uses can be found here.

First, here is the controller to be tested :

using System.Web.Mvc;

namespace MyApp.Controllers
{
    public class EmailController : Controller
    {
        private IEmailService _emailService;

        public EmailController(IEmailService emailService)
        {
            _emailService = emailService;
        }

        // Allows to verify if an email already exists
        [HttpPost]
        public ActionResult VerifyEmail(string email)
        {
            if (_emailService.VerifyEmail(email))
                return RedirectToAction("ProceedRegistration");

            return Content("Email already used!");
        }

       public ActionResult ProceedRegistration()
        {
            return View();
        }
    }
}

Second, here is the sample unit test:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using MyApp.Services;
using MyApp.Controllers;
using System.Web.Mvc;


namespace TestMyApp
{
    [TestClass]
    public class TestMyApp_Isolation
    {
        //private IEmailService _mockEmailService;
        
        [TestMethod]
        public void TestRecognized()
        {
            IEmailService mockEmailService = MockRepository.GenerateMock();

            // Arrange
            mockEmailService.Expect(m => m.VerifyEmail(Arg.Is.Anything)).Return(true);
            EmailController emailController = new EmailController(mockEmailService);

            // Act
            var result = emailController.VerifyEmail(Arg.Is.Anything);

            // Assert
            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
            Assert.AreEqual("ProceedRegistration", ((RedirectToRouteResult)result).RouteValues["action"]);
        }

        [TestMethod]
        public void TestNotRecognized()
        {
            IEmailService mockEmailService = MockRepository.GenerateMock();

            // Arrange
            mockEmailService.Expect(m => m.VerifyEmail(Arg.Is.Anything)).Return(false);
            EmailController emailController = new EmailController(mockEmailService);

            // Act
            var result = emailController.VerifyEmail(Arg.Is.Anything);

            // Assert
            Assert.IsInstanceOfType(result, typeof(ContentResult));
            Assert.AreEqual("Email already used!", ((ContentResult)result).Content);
        }
    }
}

In this example I am testing the behaviour of a controller responsible for verifying the existence of an email. I want to know how it behaves when it tests an email that is already used and an email that is new.

The following are the well-known unit test stages:

  •  “Arrange” to prepare the behavior to be tested;
  • “Act” execute the items to be test;
  • “Assert” to validate the behavior of the test unit.

You will notice that I created the fake object “IEmailService mockEmailService MockRepository.GenerateMock ();” whose behaviour I “arrange” (expecting a specific behaviour from the EmailService) “mockEmailService.Expect (m => m.VerifyEmail (Arg .Is.Anything)) Return (true);”

I am now able to test the behavior of my action method in the “VerifyEmail” controller by getting the result obtained after performing the action “Act” : “var result = emailController.VerifyEmail (Arg .Is.Anything);”

Faced with an unrecognized email, the controller should redirect to another action to continue enrollment in the website. I am actually testing the controller to check whether it is actually a redirect, and whether it redirects to the right Action controller to continue the work with “Assert” :

“Assert.IsInstanceOfType (result, typeof (RedirectToRouteResult));” and “Assert.AreEqual (” ProceedRegistration “((RedirectToRouteResult) result) .RouteValues ​​[” action “]);”

Now, let’s test behavior when an email is recognized:

  1. “Arrange” : “mockEmailService.Expect(m => m.VerifyEmail(Arg.Is.Anything)).Return(false);”
  2. “Act” : “var result = emailController.VerifyEmail(Arg.Is.Anything);”
  3. “Assert” : “Assert.IsInstanceOfType(result, typeof(ContentResult));” and “Assert.AreEqual(“Email already used!”, ((ContentResult)result).Content);”

This time the expected return type is “ContentResult” with a specific error message “Email already used!”

This example has shown how to test the behavior of a controller without any dependencies, we performed a real, isolated, unit test!

Example of an integration test

Now let’s look at an integration test using the same example as previously:

Let’s assume that the concrete class “EmailService” accesses DataBase.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using MyApp.Services;
using MyApp.Controllers;
using System.Web.Mvc;

namespace TestMyApp
{
    [TestClass]
    public class TestMyApp_Integration
    {
        [TestMethod]
        public void TestRecognized()
        {
            // Arrange
            string email = "recognizedEmail@test.com";
            EmailController emailController = new EmailController(new EmailService());

            // Act
            var result = emailController.VerifyEmail(email);

            // Assert
            Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
            Assert.AreEqual("ProceedRegistration", ((RedirectToRouteResult)result).RouteValues["action"]);
        }

        [TestMethod]
        public void TestNotRecognized()
        {
            // Arrange
            string email = "NotRecognizedEmail@test.com";
            EmailController emailController = new EmailController(new EmailService());

            // Act
            var result = emailController.VerifyEmail(email);

            // Assert
            Assert.IsInstanceOfType(result, typeof(ContentResult));
            Assert.AreEqual("Email already used!", ((ContentResult)result).Content);
        }
    }
}

This example highlights the difference between this test and the unit test: I don’t set up an artificial behavior in the “Arrange” section, I have a real “email” parameter in a real class method with a call to the database!, and I check controller behavior with external dependencies during an actual use of the functionality.

I hope this example has helped you understand the difference between a unit test and an integration test. Feel free to leave any questions in the “comment” section 🙂

Now, you should be able to tell the difference between a real unit test and an integration test.