Testes unitários no C# com MSTest

Continuando a minha série de artigos sobre as principais bibliotecas de teste do C#, neste artigo abordarei a biblioteca criada e mantida pela Microsoft, a MSTest. Caso queria conhecer a NUnit ou a XUnit, não deixe de ver os artigos anteriores.

Conhecendo a biblioteca MSTest

O Microsoft Test Framework, mais conhecido como MSTest, nasceu como uma ferramenta de testes unitários para aplicações .NET integrada com o Visual Studio. Hoje ela é uma biblioteca separada, que possui recursos poderosos, porém simples e de fácil compreensão.

C# (C Sharp) - TDD
Curso de C# (C Sharp) - TDD
CONHEÇA O CURSO

Criando o projeto que será testado

Assim como nos demais artigos, iremos criar uma solução:

dotnet new sln -n teste-unitario-com-mstest

Criar um projeto de biblioteca de classes:

dotnet new classlib -n Calculos

E criar uma classe, que será testada:

public class Calculadora
{
    public int Soma(int operador1, int operador2) => operador1 + operador2;
    public int Subtracao(int operador1, int operador2) => operador1 - operador2;
    public int Multiplicao(int operador1, int operador2) => operador1 * operador2;
    public int Divisao(int dividendo, int divisor) => dividendo / divisor;
    public (int quociente, int resto) RestoDivisao(int dividendo, int divisor) => (dividendo / divisor, dividendo % divisor);
}

Por fim, é necessário adicionar a referência deste projeto na solução:

dotnet sln teste-unitario-com-mstest.sln add Calculos/Calculos.csproj

Criando o projeto de teste

Sabemos que um projeto de teste se trata de um projeto de biblioteca de classes que contém a referência de uma biblioteca de teste. Felizmente, o .NET fornece um template que já cria um projeto com a referência da biblioteca de teste. Para o MSTest o projeto pode ser criado com o comando abaixo:

dotnet new mstest -n Calculos.Tests

Este projeto será adicionado na solução:

dotnet sln teste-unitario-com-mstest.sln add Calculos.Tests/Calculos.Tests.csproj

E o projeto Calculos será referenciado nele:

dotnet add Calculos.Tests/Calculos.Tests.csproj reference Calculos/Calculos.csproj

Agora podemos conhecer os recursos desta biblioteca.

Adicionando os testes unitários

No projeto de teste, Calculos.Tests exclua o arquivo TestUnit1.cs e adicione um novo arquivo chamado CalculadoraTests.cs, neste arquivo iremos criar uma classe com o mesmo nome, que terá a estrutura abaixo:

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Calculos.Tests
{
    [TestClass]
    public class CalculadoraTests
    {
        [TestMethod]
        public void Soma_DeveRetornarOValorCorreto()
        {
            Calculadora c = new Calculadora();
            var resultado = c.Soma(10, 20);
            //Verifica se o resultado é igual a 30
            Assert.AreEqual(30, resultado);
        }
    }
}

Observe que é utilizado o atributo TestClass para indicar que a classe criada é uma classe de teste. Dentro dela, há um método marcado com o atributo TestMethod, que sinaliza que este é um método de teste.

Quando o runner da biblioteca for executado, ele irá analisar dentro do projeto quais são as classes que possuem o atributo TestClass e irá chamar os métodos marcados com o atributo TestMethod.

Diferente de outras bibliotecas, o runner da MSTest não é executado diretamente, ele é chamado quando o teste é executado utilizando o comando dotnet test ou Test Explorer do Visual Studio.

Para este artigo, utilizarei a linha de comando:

Note que o único teste definido passou.

Definindo vários testes unitários de uma só vez

No momento a nossa classe de teste possui apenas um teste unitário, que analisa um grupo específico de dados de entrada. Caso seja necessário analisar vários dados de entrada, pelo que vimos até o momento, seria necessário criar vários testes.

Felizmente o MSTest possui os atributos DataTestMethod e DataRow que permite criar um método de teste, que varia apenas os dados de entrada:

[DataTestMethod]
[DataRow(1)]
[DataRow(2)]
[DataRow(3)]
[DataRow(4)]
public void RestoDivisao_DeveRetornarZero(int value)
{
    Calculadora c = new Calculadora();
    var resultado = c.RestoDivisao(12, value);
    //Verifica se o resto da divisão é 0
    Assert.AreEqual(0, resultado.resto);
}

Ao executar os testes:

Note que cada dado de entrada informado nos DataRow é considerado um teste a parte e o grupo é considerado outro teste. É por isso que a contagem de testes é 6.

Se o teste não passar com um dos valores:

[DataTestMethod]
[DataRow(1)]
[DataRow(2)]
[DataRow(3)]
[DataRow(5)]
public void RestoDivisao_DeveRetornarZero(int value)
{
    Calculadora c = new Calculadora();
    var resultado = c.RestoDivisao(12, value);
    //Verifica se o resto da divisão é 0
    Assert.AreEqual(0, resultado.resto);
}

Teremos o resultado:

Ou seja, um dos testes não passou, assim é indicado que o grupo também não passou. Por isso que é indicado dois erros.

Para finalizar, e obter uma cobertura de 100% dos testes, vamos definir método de testes para os outros métodos da nossa classe de Calculadora:

[TestClass]
public class CalculadoraTests
{
    [TestMethod]
    public void Soma_DeveRetornarOValorCorreto()
    {
        Calculadora c = new Calculadora();
        var resultado = c.Soma(10, 20);
        //Verifica se o resultado é igual a 30
        Assert.AreEqual(30, resultado);
    }

    [DataTestMethod]
    [DataRow(1)]
    [DataRow(2)]
    [DataRow(3)]
    [DataRow(4)]
    public void RestoDivisao_DeveRetornarZero(int value)
    {
        Calculadora c = new Calculadora();
        var resultado = c.RestoDivisao(12, value);
        //Verifica se o resto da divisão é 0
        Assert.AreEqual(0, resultado.resto);
    }

    [TestMethod]
    public void RestoDivisao_DeveRetornarOValorCorreto()
    {
        Calculadora c = new Calculadora();
        var resultado = c.RestoDivisao(10, 3);
        //Verifica se o quociente da divisão é 3 e o resto 1
        Assert.AreEqual(3, resultado.quociente);
        Assert.AreEqual(1, resultado.resto);
    }

    [TestMethod]
    public void Subtracao_DeveRetornarOValorCorreto()
    {
        Calculadora c = new Calculadora();
        var resultado = c.Subtracao(20, 10);
        //Verifica se o resultado é igual a 10
        Assert.AreEqual(10, resultado);
    }

    [TestMethod]
    public void Divisao_DeveRetornarOValorCorreto()
    {
        Calculadora c = new Calculadora();
        var resultado = c.Divisao(100, 10);
        //Verifica se o resultado é igual a 10
        Assert.AreEqual(10, resultado);
    }

    [TestMethod]
    public void Multiplicao_DeveRetornarOValorCorreto()
    {
        Calculadora c = new Calculadora();
        var resultado = c.Multiplicao(5, 2);
        //Verifica se o resultado é igual a 10
        Assert.AreEqual(10, resultado);
    }
}
C# (C Sharp) - Introdução ao ASP.NET Core
Curso de C# (C Sharp) - Introdução ao ASP.NET Core
CONHEÇA O CURSO

Demais comparadores do MSTest

Nos exemplos apresentados neste artigo, utilizamos somente o comparador AreEqual. Felizmente a biblioteca fornece uma série de comparadores que podem ser visualizados na documentação dela.

Sendo uma das bibliotecas de testes unitários mais simples do C#, com ela não há desculpa para não adicionar testes unitários nas suas aplicações.

Fico por aqui, até o próximo artigo.

Deixe seu comentário

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.