Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O teste orientado por dados permite executar o mesmo método de teste com múltiplos conjuntos de dados de entrada. Em vez de escrever métodos de teste separados para cada caso de teste, defina a sua lógica de teste uma vez e forneça diferentes entradas através de atributos ou fontes de dados externas.
Visão geral
O MSTest fornece vários atributos para testes orientados por dados:
| Attribute | Caso de uso | Melhor para |
|---|---|---|
DataRow |
Dados de teste em linha | Casos de teste simples e estáticos |
DynamicData |
Dados provenientes de métodos, propriedades ou campos | Dados de teste complexos ou computados |
TestDataRow<T> |
Dados melhorados com metadados | Casos de teste que necessitam de nomes ou categorias de visualização |
DataSource |
Ficheiros de dados externos ou bases de dados | Cenários legados com fontes de dados externas |
ITestDataSource |
Atributos personalizados da fonte de dados | Cenários totalmente personalizados orientados por dados |
Sugestão
Para testes combinatórios (testando todas as combinações de múltiplos conjuntos de parâmetros), utilize o pacote de código aberto Combinatorial.MSTest NuGet. Este pacote mantido pela comunidade está disponível no GitHub , mas não é mantido pela Microsoft.
DataRowAttribute
Permite-te DataRowAttribute executar o mesmo método de teste com múltiplas entradas diferentes. Aplicar um ou vários DataRow atributos a um método de teste e combiná-lo com o TestMethodAttribute.
O número e os tipos de argumentos devem corresponder exatamente à assinatura do método de teste.
Sugestão
Analisadores relacionados:
-
MSTEST0014 valida que
DataRowos argumentos correspondem à assinatura do método de teste. -
MSTEST0042 deteta entradas duplicadas
DataRowque executariam o mesmo caso de teste várias vezes.
Utilização básica
[TestClass]
public class CalculatorTests
{
[TestMethod]
[DataRow(1, 2, 3)]
[DataRow(0, 0, 0)]
[DataRow(-1, 1, 0)]
[DataRow(100, 200, 300)]
public void Add_ReturnsCorrectSum(int a, int b, int expected)
{
var calculator = new Calculator();
Assert.AreEqual(expected, calculator.Add(a, b));
}
}
Tipos de argumentos suportados
DataRow suporta vários tipos de argumentos, incluindo primitivas, strings, arrays e valores nulos:
[TestClass]
public class DataRowExamples
{
[TestMethod]
[DataRow(1, "message", true, 2.0)]
public void TestWithMixedTypes(int i, string s, bool b, float f)
{
// Test with different primitive types
}
[TestMethod]
[DataRow(new string[] { "line1", "line2" })]
public void TestWithArray(string[] lines)
{
Assert.AreEqual(2, lines.Length);
}
[TestMethod]
[DataRow(null)]
public void TestWithNull(object o)
{
Assert.IsNull(o);
}
[TestMethod]
[DataRow(new string[] { "a", "b" }, new string[] { "c", "d" })]
public void TestWithMultipleArrays(string[] input, string[] expected)
{
// Starting with MSTest v3, two arrays don't need wrapping
}
}
Utilização de parâmetros para argumentos de variáveis
Use a params palavra-chave para aceitar um número variável de argumentos:
[TestClass]
public class ParamsExample
{
[TestMethod]
[DataRow(1, 2, 3, 4)]
[DataRow(10, 20)]
[DataRow(5)]
public void TestWithParams(params int[] values)
{
Assert.IsTrue(values.Length > 0);
}
}
Nomes de exibição personalizados
Defina a DisplayName propriedade para personalizar como os casos de teste aparecem no Explorador de Testes:
[TestClass]
public class DisplayNameExample
{
[TestMethod]
[DataRow(1, 2, DisplayName = "Functional Case FC100.1")]
[DataRow(3, 4, DisplayName = "Edge case: small numbers")]
public void TestMethod(int i, int j)
{
Assert.IsTrue(i < j);
}
}
Sugestão
Para maior controlo sobre os metadados de teste, considere usar TestDataRow<T> com DynamicData.
TestDataRow<T> suporta mostrar nomes juntamente com categorias de teste e ignorar mensagens para casos de teste individuais.
Ignorar casos de teste específicos
A partir do MSTest v3.8, use a IgnoreMessage propriedade para saltar linhas de dados específicas:
[TestClass]
public class IgnoreDataRowExample
{
[TestMethod]
[DataRow(1, 2)]
[DataRow(3, 4, IgnoreMessage = "Temporarily disabled - bug #123")]
[DataRow(5, 6)]
public void TestMethod(int i, int j)
{
// Only the first and third data rows run
// The second is skipped with the provided message
}
}
DynamicDataAttribute
O DynamicDataAttribute permite-lhe fornecer dados de teste a partir de métodos, propriedades ou campos. Use este atributo quando os dados de teste forem complexos, calculados dinamicamente ou demasiado verbosos para atributos inline DataRow .
Tipos de fontes de dados suportados
A fonte de dados pode devolver qualquer IEnumerable<T> onde T seja um dos tipos listados na tabela seguinte. Qualquer coleção que implemente IEnumerable<T> funcione, incluindo List<T>, arrays como T[] ou tipos de coleções personalizadas. Escolha com base nas suas necessidades:
| Tipo de retorno | Segurança de tipo | Suporte de metadados | Melhor para |
|---|---|---|---|
ValueTuple (por exemplo, (int, string)) |
Tempo de compilação | Não | A maioria dos cenários apresenta sintaxe simples com verificação completa de tipos. |
Tuple<...> |
Tempo de compilação | Não | Quando não consegues usar ValueTuple |
TestDataRow<T> |
Tempo de compilação | Yes | Casos de teste que necessitam de nomes de exibição, categorias ou ignorar mensagens |
object[] |
** Somente tempo de execução | Não | Código legado - a evitar para novos testes |
Sugestão
Para novos métodos de dados de teste, use ValueTuple para casos simples ou TestDataRow<T> quando precisar de metadados. Evite object[] porque não tem verificação de tipos em tempo de compilação e pode causar erros de execução devido a desajustes de tipos.
Fontes de dados
A fonte de dados pode ser um método, propriedade ou campo. Os três são intercambiáveis — escolha com base na sua preferência:
[TestClass]
public class DynamicDataExample
{
// Method - best for computed or yielded data
public static IEnumerable<(int Value, string Name)> GetTestData()
{
yield return (1, "first");
yield return (2, "second");
}
// Property - concise for static data
public static IEnumerable<(int Value, string Name)> TestDataProperty =>
[
(1, "first"),
(2, "second")
];
// Field - simplest for static data
public static IEnumerable<(int Value, string Name)> TestDataField =
[
(1, "first"),
(2, "second")
];
[TestMethod]
[DynamicData(nameof(GetTestData))]
public void TestWithMethod(int value, string name)
{
Assert.IsTrue(value > 0);
}
[TestMethod]
[DynamicData(nameof(TestDataProperty))]
public void TestWithProperty(int value, string name)
{
Assert.IsTrue(value > 0);
}
[TestMethod]
[DynamicData(nameof(TestDataField))]
public void TestWithField(int value, string name)
{
Assert.IsTrue(value > 0);
}
}
Observação
Os métodos, propriedades e campos da fonte de dados devem ser public static e devolver um IEnumerable<T> de um tipo suportado.
Sugestão
Analisador relacionado: MSTEST0018 valida que a fonte de dados existe, é acessível e tem a assinatura correta.
Fonte de dados de uma classe diferente
Especifique uma classe diferente usando o parâmetro type:
public class TestDataProvider
{
public static IEnumerable<object[]> GetTestData()
{
yield return new object[] { 1, "first" };
yield return new object[] { 2, "second" };
}
}
[TestClass]
public class DynamicDataExternalExample
{
[TestMethod]
[DynamicData(nameof(TestDataProvider.GetTestData), typeof(TestDataProvider))]
public void TestMethod(int value1, string value2)
{
Assert.IsTrue(value1 > 0);
}
}
Nomes de exibição personalizados
Customize nomes de exibição de casos de teste usando a propriedade DynamicDataDisplayName.
using System.Reflection;
[TestClass]
public class DynamicDataDisplayNameExample
{
[TestMethod]
[DynamicData(nameof(GetTestData), DynamicDataDisplayName = nameof(GetDisplayName))]
public void TestMethod(int value1, string value2)
{
Assert.IsTrue(value1 > 0);
}
public static IEnumerable<object[]> GetTestData()
{
yield return new object[] { 1, "first" };
yield return new object[] { 2, "second" };
}
public static string GetDisplayName(MethodInfo methodInfo, object[] data)
{
return $"{methodInfo.Name} with value {data[0]} and '{data[1]}'";
}
}
Observação
O método do nome de exibição deve ser public static, devolver um string, e aceitar dois parâmetros: MethodInfo e object[].
Sugestão
Para uma abordagem mais simples aos nomes de visualização personalizados, considere usar TestDataRow<T> com a sua DisplayName propriedade em vez de um método separado.
Ignorar todos os casos de teste de uma fonte de dados
A partir do MSTest v3.8, utiliza-se IgnoreMessage para saltar todos os casos de teste:
[TestClass]
public class IgnoreDynamicDataExample
{
[TestMethod]
[DynamicData(nameof(GetTestData), IgnoreMessage = "Feature not ready")]
public void TestMethod(int value1, string value2)
{
// All test cases from GetTestData are skipped
}
public static IEnumerable<object[]> GetTestData()
{
yield return new object[] { 1, "first" };
yield return new object[] { 2, "second" };
}
}
Sugestão
Para ignorar casos de teste individuais, use TestDataRow<T> com a propriedade IgnoreMessage. Veja a secção TestDataRow<T> .
TestDataRow
A TestDataRow<T> classe proporciona controlo melhorado sobre os dados de teste em testes orientados por dados. Use IEnumerable<TestDataRow<T>> como tipo de retorno da sua fonte de dados para especificar:
- Nomes de exibição personalizados: Defina um nome de exibição único por cada caso de teste
- Categorias de teste: Anexar metadados a casos de teste individuais
- Ignorar mensagens: Omitir casos de teste específicos com justificações
- Dados com segurança de tipo: Use genéricos para dados de teste fortemente tipados
Utilização básica
[TestClass]
public class TestDataRowExample
{
[TestMethod]
[DynamicData(nameof(GetTestDataRows))]
public void TestMethod(int value1, string value2)
{
Assert.IsTrue(value1 > 0);
}
public static IEnumerable<TestDataRow> GetTestDataRows()
{
yield return new TestDataRow((1, "first"))
{
DisplayName = "Test Case 1: Basic scenario",
};
yield return new TestDataRow((2, "second"))
{
DisplayName = "Test Case 2: Edge case",
TestCategories = ["HighPriority", "Critical"],
};
yield return new TestDataRow((3, "third"))
{
IgnoreMessage = "Not yet implemented",
};
}
}
DataSourceAttribute
Observação
DataSource está disponível apenas no .NET Framework. Para projetos .NET (Core), use DataRow ou DynamicData em vez disso.
Liga DataSourceAttribute testes a fontes de dados externas como ficheiros CSV, ficheiros XML ou bases de dados.
Para obter informações mais pormenorizadas, consulte:
- Criar um teste unitário orientado por dados
- Use um ficheiro de configuração para definir uma fonte de dados
ITestDataSource
A ITestDataSource interface permite-lhe criar atributos de fonte de dados totalmente personalizados. Implemente esta interface quando precisar de comportamentos que os atributos incorporados não suportam, como gerar dados de teste com base em variáveis de ambiente, ficheiros de configuração ou outras condições de execução.
Membros da interface
A interface define dois métodos:
| Método | Propósito |
|---|---|
GetData(MethodInfo) |
Devolve dados de teste como IEnumerable<object?[]> |
GetDisplayName(MethodInfo, object?[]?) |
Devolve o nome de exibição para um caso de teste |
Criação de um atributo de fonte de dados personalizado
Para criar uma fonte de dados personalizada, defina uma classe de atributos que herde de Attribute e implemente ITestDataSource:
using System.Globalization;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class MyDataSourceAttribute : Attribute, ITestDataSource
{
public IEnumerable<object?[]> GetData(MethodInfo methodInfo)
{
// Return test data based on your custom logic
yield return [1, "first"];
yield return [2, "second"];
yield return [3, "third"];
}
public string? GetDisplayName(MethodInfo methodInfo, object?[]? data)
{
return data is null
? null
: string.Format(CultureInfo.CurrentCulture, "{0} ({1})", methodInfo.Name, string.Join(",", data));
}
}
[TestClass]
public class CustomDataSourceExample
{
[TestMethod]
[MyDataSource]
public void TestWithCustomDataSource(int value, string name)
{
Assert.IsTrue(value > 0);
Assert.IsNotNull(name);
}
}
Exemplo do mundo real: dados de teste baseados no ambiente
Este exemplo mostra um atributo personalizado que gera dados de teste com base em frameworks de destino, filtrando com base no sistema operativo:
using System.Globalization;
using System.Reflection;
[AttributeUsage(AttributeTargets.Method)]
public class TargetFrameworkDataAttribute : Attribute, ITestDataSource
{
private readonly string[] _frameworks;
public TargetFrameworkDataAttribute(params string[] frameworks)
{
_frameworks = frameworks;
}
public IEnumerable<object?[]> GetData(MethodInfo methodInfo)
{
bool isWindows = OperatingSystem.IsWindows();
foreach (string framework in _frameworks)
{
// Skip .NET Framework on non-Windows platforms
if (!isWindows && framework.StartsWith("net4", StringComparison.Ordinal))
{
continue;
}
yield return [framework];
}
}
public string? GetDisplayName(MethodInfo methodInfo, object?[]? data)
{
return data is null
? null
: string.Format(CultureInfo.CurrentCulture, "{0} ({1})", methodInfo.Name, data[0]);
}
}
[TestClass]
public class CrossPlatformTests
{
[TestMethod]
[TargetFrameworkData("net48", "net8.0", "net9.0")]
public void TestOnMultipleFrameworks(string targetFramework)
{
// Test runs once per applicable framework
Assert.IsNotNull(targetFramework);
}
}
Sugestão
Para casos simples em que só precisa de personalizar nomes de visualização ou adicionar metadados, considere usar TestDataRow<T> com DynamicData em vez de implementar ITestDataSource. Reserve implementações personalizadas ITestDataSource para cenários que exijam filtragem dinâmica ou lógica complexa de geração de dados.
Estratégia de desdobramento
Os atributos de teste orientados por dados suportam a TestDataSourceUnfoldingStrategy propriedade, que controla como os casos de teste aparecem nos resultados do Explorador de Testes e do TRX. Esta propriedade também determina se pode executar casos de teste individuais de forma independente.
Estratégias disponíveis
| Estratégia | Comportamento |
|---|---|
Auto (padrão) |
A MSTest determina a melhor estratégia de desdobramento |
Unfold |
Todos os casos de teste são expandidos e apresentados individualmente |
Fold |
Todos os casos de teste são agregados num nó único de teste |
Quando mudar a estratégia
Na maioria dos cenários, o comportamento padrão Auto proporciona o melhor equilíbrio. Considere alterar esta definição apenas quando tiver requisitos específicos:
- Fontes de dados não determinísticas
- Limitações ou bugs conhecidos no MSTest
- Preocupações com o desempenho em muitos casos de teste
Exemplo de utilização
[TestClass]
public class UnfoldingExample
{
[TestMethod(UnfoldingStrategy = TestDataSourceUnfoldingStrategy.Unfold)] // That's the default behavior
[DataRow(1)]
[DataRow(2)]
[DataRow(3)]
public void TestMethodWithUnfolding(int value, string text)
{
// Each test case appears individually in Test Explorer
}
[TestMethod(UnfoldingStrategy = TestDataSourceUnfoldingStrategy.Fold)]
[DynamicData(nameof(GetData))]
public void TestMethodWithFolding(int value, string text)
{
// All test cases appear as a single collapsed node
}
public static IEnumerable<(int, string)> GetData()
{
yield return (1, "one");
yield return (2, "two");
yield return (3, "three");
}
}
Melhores práticas
Escolha o atributo certo: Use
DataRowpara dados simples e em linha. UsoDynamicDatapara dados complexos ou computados.Nomeie os seus casos de teste: Use
DisplayNamepara facilitar a identificação das falhas de teste.Mantenha as fontes de dados próximas: Defina as fontes de dados na mesma classe sempre que possível para melhor manutenção.
Utilize dados significativos: Escolha dados de teste que exijam casos de limite e condições de limite.
Considere o teste combinatório: Para testar combinações de parâmetros, utilize o pacote Combinatorial.MSTest .