Como executar um método de teste com vários parâmetros no MSTest?

140

O NUnit possui um recurso chamado Valores, como abaixo:

[Test]
public void MyTest(
    [Values(1,2,3)] int x,
    [Values("A","B")] string s)
{
    // ...
}

Isso significa que o método de teste será executado 6 vezes:

MyTest(1, "A")
MyTest(1, "B")
MyTest(2, "A")
MyTest(2, "B")
MyTest(3, "A")
MyTest(3, "B")

Estamos usando o MSTest agora, existe algum equivalente para isso, para que eu possa executar o mesmo teste com vários parâmetros?

[TestMethod]
public void Mytest()
{
    // ...
}
A luz
fonte
Você pode usar o MSTestHacks, conforme descrito na resposta stackoverflow.com/a/19536942/52277 .
Michael Freidgeim
Possível duplicata de Como RowTest com MSTest?
Michael Freidgeim
@MichaelFreidgeim Esta pergunta tem respostas melhores do que o seu alvo sugerido
Rob
1
@ Rob: IMHO, a resposta mais adequada -MSTestHacks - Como RowTest com MSTest? está faltando nesta pergunta.
Michael Freidgeim
@MichaelFreidgeim Talvez, embora pareça que a funcionalidade já exista há 3 anos e meio ( stackoverflow.com/questions/9021881/… )
Rob

Respostas:

46

Infelizmente, ele não é suportado no MSTest. Aparentemente, existe um modelo de extensibilidade e você pode implementá-lo . Outra opção seria usar testes orientados a dados .

Minha opinião pessoal seria apenas ficar com o NUnit ...

Edição: a partir do Visual Studio 2012, atualização 1, o MSTest tem um recurso semelhante. Veja a resposta de @ McAden abaixo.

jeroenh
fonte
Estamos usando o Selenium, que gera o código NUnit, então trocamos para usar o NUnit :) #
The Light
4
Descobri que algo semelhante agora é possível na Atualização 1 do Visual Studio 2012, apenas a FYI para consideração futura de qualquer pessoa que esteja olhando para esta resposta.
21312 McAden
@McAden você tem um link com uma explicação?
jeroenh
6
Dei uma resposta abaixo com um exemplo e um link para o meu blog. Ele menciona os atributos necessários e também a propriedade "DisplayName" no atributo que distingue os casos no Test Explorer. Também foi mencionado no anúncio de outubro do CTP (que agora tem o lançamento oficial) blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/… Adicionei as informações a essa pergunta do SO porque passou bastante tempo procurando por ele. Espero que isso poupe a alguém algum tempo.
22468 McAden
167

EDIT 4 : Parece que isso foi concluído no MSTest V2 17 de junho de 2016: https://blogs.msdn.microsoft.com/visualstudioalm/2016/06/06/17/taking-the-mstest-framework-forward-with-mstest- v2 /

Resposta original :

Há cerca de uma semana, no Visual Studio 2012 Update 1, algo semelhante agora é possível:

[DataTestMethod]
[DataRow(12,3,4)]
[DataRow(12,2,6)]
[DataRow(12,4,3)]
public void DivideTest(int n, int d, int q)
{
  Assert.AreEqual( q, n / d );
}

EDIT : Parece que isso só está disponível no projeto de teste de unidade do WinRT / Metro . Vadio

EDIT 2 : A seguir, os metadados encontrados usando "Ir para a definição" no Visual Studio:

#region Assembly Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll, v11.0.0.0
// C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\MSTestFramework\11.0\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll
#endregion

using System;

namespace Microsoft.VisualStudio.TestPlatform.UnitTestFramework
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class DataTestMethodAttribute : TestMethodAttribute
    {
        public DataTestMethodAttribute();

        public override TestResult[] Execute(ITestMethod testMethod);
    }
}

EDIT 3 : Esse problema foi levantado nos fóruns do UserVoice do Visual Studio. Estados da última atualização:

INÍCIO · Equipe do Visual Studio ADMIN A equipe do Visual Studio (Equipe do produto, Microsoft Visual Studio) respondeu · 25 de abril de 2016 Obrigado pelo feedback. Começamos a trabalhar nisso.

Pratap Lakshman Visual Studio

https://visualstudio.uservoice.com/forums/330519-team-services/suggestions/3865310-allow-use-of-datatestmethod-datarow-in-all-unit

McAden
fonte
4
Windows Phone é agora suportado também, com o Visual Studio 2012 Update 2 (atualmente, CTP 4)
Pedro Lamas
8
Eu tenho a atualização 1, mas DataTestMethod e DataRow não são reconhecidos. Em qual biblioteca esses atributos estão?
DevDave
3
Existe alguma fonte oficial sobre o DataTestMethod? Em que namespace está, em qual assembly?
Igor Lankin
2
Descobri que o UnitTestFramework.dll estava instalado no meu computador e, depois de referenciá-lo manualmente, consegui escrever um método usando o atributo [DataTestMethod] com linhas de dados, mas não consigo obter o Test Explorer no Visual Studio 2012.3 para encontrar o método.
21413 Josh DeLong
5
Eu fui para o caminho do arquivo "C: \ Arquivos de programas (x86) \ Microsoft SDKs \ Windows \ v8.0 \ ExtensionSDKs \ MSTestFramework \ 11.0 \ References \ CommonConfiguration \ neutral \ Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll" no meu computador e o arquivo estava lá. Então, eu o referenciei no meu projeto básico de teste de unidade. Abrir a dll no JustDecompile mostra que a biblioteca possui apenas referências ao mscorlib, System e System.Core. Não é um projeto da Windows Store.
Josh DeLong
34

Esse recurso está em pré-lançamento agora e funciona com o VS 2015.

Por exemplo:

[TestClass]
public class UnitTest1
{
    [DataTestMethod]
    [DataRow(1, 2, 2)]
    [DataRow(2, 3, 5)]
    [DataRow(3, 5, 8)]
    public void AdditionTest(int a, int b, int result)
    {
        Assert.AreEqual(result, a + b);
    }
}
Pompair
fonte
Essa é a resposta correta. Observe que não é necessário dizer [DataTestMethod] para usar o [DataRow] ( stackoverflow.com/a/59162403/2540235 )
mattavatar
11

Como ninguém mencionou - não exatamente o mesmo que os atributos de NUnit Value(ou TestCase), mas o MSTest tem DataSourceatributo, o que permite que você faça coisas semelhantes. Você pode conectá-lo ao banco de dados ou arquivo XML - não tão direto quanto o recurso do NUnit, mas faz o trabalho.

km
fonte
6

É muito simples de implementar - você deve usar TestContextproperty e TestPropertyAttribute.

Exemplo

public TestContext TestContext { get; set; }
private List<string> GetProperties()
{
    return TestContext.Properties
        .Cast<KeyValuePair<string, object>>()
        .Where(_ => _.Key.StartsWith("par"))
        .Select(_ => _.Value as string)
        .ToList();
}

//usage
[TestMethod]
[TestProperty("par1", "http://getbootstrap.com/components/")]
[TestProperty("par2", "http://www.wsj.com/europe")]
public void SomeTest()
{
    var pars = GetProperties();
    //...
}

EDITAR:

Eu preparei alguns métodos de extensão para simplificar o acesso à TestContextpropriedade e agir como se tivéssemos vários casos de teste. Veja o exemplo com o processamento de propriedades simples de teste aqui:

[TestMethod]
[TestProperty("fileName1", @".\test_file1")]
[TestProperty("fileName2", @".\test_file2")]
[TestProperty("fileName3", @".\test_file3")]
public void TestMethod3()
{
    TestContext.GetMany<string>("fileName").ForEach(fileName =>
    {
        //Arrange
        var f = new FileInfo(fileName);

        //Act
        var isExists = f.Exists;

        //Asssert
        Assert.IsFalse(isExists);
    });
}

e exemplo com a criação de objetos de teste complexos:

[TestMethod]
//Case 1
[TestProperty(nameof(FileDescriptor.FileVersionId), "673C9C2D-A29E-4ACC-90D4-67C52FBA84E4")]
//...
public void TestMethod2()
{
    //Arrange
    TestContext.For<FileDescriptor>().Fill(fi => fi.FileVersionId).Fill(fi => fi.Extension).Fill(fi => fi.Name).Fill(fi => fi.CreatedOn, new CultureInfo("en-US", false)).Fill(fi => fi.AccessPolicy)
        .ForEach(fileInfo =>
        {
            //Act
            var fileInfoString = fileInfo.ToString();

            //Assert
            Assert.AreEqual($"Id: {fileInfo.FileVersionId}; Ext: {fileInfo.Extension}; Name: {fileInfo.Name}; Created: {fileInfo.CreatedOn}; AccessPolicy: {fileInfo.AccessPolicy};", fileInfoString);
        });
}

Dê uma olhada nos métodos de extensão e no conjunto de amostras para obter mais detalhes.

Andrey Burykin
fonte
2
Essa abordagem funciona, mas não cria casos de teste individuais para cada conjunto de parâmetros.
usr4896260
Você pode usar algo mais complexo como o valor TestProperty (por exemplo, "0-100"), analisar e manipular isso no corpo do teste.
Andrey Burykin
4

Há, é claro, outra maneira de fazer isso que não foi discutida neste segmento, ou seja, por herança da classe que contém o TestMethod. No exemplo a seguir, apenas um TestMethod foi definido, mas dois casos de teste foram feitos.

No Visual Studio 2012, ele cria dois testes no TestExplorer:

  1. DemoTest_B10_A5.test
  2. DemoTest_A12_B4.test

    public class Demo
    {
        int a, b;
    
        public Demo(int _a, int _b)
        {
            this.a = _a;
            this.b = _b;
        }
    
        public int Sum()
        {
            return this.a + this.b;
        }
    }
    
    public abstract class DemoTestBase
    {
        Demo objUnderTest;
        int expectedSum;
    
        public DemoTestBase(int _a, int _b, int _expectedSum)
        {
            objUnderTest = new Demo(_a, _b);
            this.expectedSum = _expectedSum;
        }
    
        [TestMethod]
        public void test()
        {
            Assert.AreEqual(this.expectedSum, this.objUnderTest.Sum());
        }
    }
    
    [TestClass]
    public class DemoTest_A12_B4 : DemoTestBase
    {
        public DemoTest_A12_B4() : base(12, 4, 16) { }
    }
    
    public abstract class DemoTest_B10_Base : DemoTestBase
    {
        public DemoTest_B10_Base(int _a) : base(_a, 10, _a + 10) { }
    }
    
    [TestClass]
    public class DemoTest_B10_A5 : DemoTest_B10_Base
    {
        public DemoTest_B10_A5() : base(5) { }
    }
Soumya Dutta
fonte
3

Não consegui fazer com que o A DataRowAttributefuncionasse no Visual Studio 2015, foi com isso que acabei:

[TestClass]
public class Tests
{
    private Foo _toTest;

    [TestInitialize]
    public void Setup()
    {
        this._toTest = new Foo();       
    }

    [TestMethod]
    public void ATest()
    {
        this.Perform_ATest(1, 1, 2);
        this.Setup();

        this.Perform_ATest(100, 200, 300);
        this.Setup();

        this.Perform_ATest(817001, 212, 817213);
        this.Setup();

    }

    private void Perform_ATest(int a, int b, int expected)
    {
        //Obviously this would be way more complex...

        Assert.IsTrue(this._toTest.Add(a,b) == expected);    
    }
}

public class Foo
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

A solução real aqui é usar apenas o NUnit (a menos que você esteja preso no MSTest como eu estou neste caso específico).

Brandon
fonte
3
você deve dividir cada chamada de teste em um teste separado, para economizar seu tempo quando uma delas for interrompida. (que todos sabemos irá acontecer)
prata
Sim, claro. Na prática, é assim que isso seria feito. Neste caso, eu estava apenas ilustrando-o pela simplicidade
Brandon