Как повторно запустить модульный тест .NET с набором декартовых параметров - PullRequest
3 голосов
/ 04 июня 2010

У меня есть 1 метод модульного тестирования, который требует нескольких параметров. Я хотел бы запустить этот тест один раз для каждого возможного значения декартовой системы с предопределенным списком для каждого параметра. Я предполагаю, что параметры могут быть переданы через тестовый контекст, но я не хочу подключаться к внешней базе данных.

Например: если бы у меня было 2 параметра со следующими возможными значениями, тест выполнялся бы 6 раз (порядок не имеет значения). (Псевдо-код)

p1 = { 1, 5, 10 }
p2 = { "blue", "red" }

test 1: ( 1, "red" )
test 2: ( 5, "red" )
test 3: ( 10, "red" )
test 4: ( 1, "blue" )
test 5: ( 5, "blue" )
test 6: ( 10, "blue" )

Примечание. Я использую встроенное модульное тестирование Visual Studio 2010, а не NUnit или одну из многих других платформ модульных тестов.

Edit:

Я храню возможные значения как перечисления в тестовом классе, но также разумно использовать массивы. Моя цель - автоматизировать связь между перечислениями / массивами источника и самим тестом. В то время как мой образец имеет только 2 параметра с 6 перестановками, фактический набор намного больше. Я не хочу пропускать сценарий только потому, что что-то пропустил при ручном преобразовании.

Ответы [ 5 ]

4 голосов
/ 09 марта 2011

вы можете сделать это с помощью такого инструмента, как Gallio в .net

[Test]
[Row(0, 0)]
[Row(1, 1)]
public void Lower_bounds(int x, int expectedResult)
{
   int result = Fibonacci.Calculate(x);
   Assert.AreEqual(expectedResult, result);
}

Совет 1: Вы можете расширить это, узнав об атрибуте [Factory] в Gallio. Совет 2: по парам поможет вам создать комбинацию

Спасибо, Jeroen, за редактирование кода и поддержку

3 голосов
/ 04 июня 2010

Для этого типа тестирования обязательно рассмотрите Pex вместо того, чтобы свернуть свое собственное.

Однако почему бы не создать внешний тест, который генерирует все комбинации из ваших наборов во время выполнения и вызывает метод теста один раз для каждой комбинации?

2 голосов
/ 04 июня 2010

Ответ на ваш вопрос: Вы можете использовать «Тесты на основе данных». Вы можете хранить свои значения в файлах с разделителями-запятыми, XML-файлах или файлах базы данных SQL. Я делал это с VS2k8, поэтому ваш процесс с VS2k10 может немного отличаться.

Сначала создайте файл с вашими тестовыми данными. Если вы создаете файл CSV, он может выглядеть как

param1, param2
1, синий
1, красный
5, синий
5, красный
10, красный
10, синий

Перейдите в «Просмотр теста», выберите тест, с которым вы хотите использовать данные. В свойствах щелкните многоточие рядом с «Строка подключения к данным». Укажите ваш файл.

Теперь в коде модульного теста вы будете указывать данные из вашего файла как testContext.DataRow("param1") и testContext.DataRow("param2").

Когда вы запустите тест, вы получите результат теста для каждой строки данных, с которой выполняется тест. Как удобно!

Обновление Если вы хотите автоматически использовать декартовы произведения параметров, которые хранятся в виде перечислений, вы можете использовать вложенные циклы типа

dim testResults в виде словаря (триплета, строки)
для каждого x как foo в fooCollection
для каждого y в качестве бара в barCollection
для каждого z как foobar в foobarCollection Пытаться 'тестовый код
testResults.add (новый триплет (x, y, z), "PASS")
поймать экс как исключение
testResults.add (новый триплет (x, y, z), «ОШИБКА:» + ex.toString ())
Конец попытки

0 голосов
/ 22 июня 2010

@ Идея Rising Star об использовании управляемых данными была лучшим решением. Я использовал это вместе со скриптом T4 для генерации CSV, содержащего декартовы перечисления. Вот скрипт для вашей справки (использует T4 Toolbox ).

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".csv" #>
<#@ include file="T4Toolbox.tt" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System.Collections.Generic" #>
<#
    List<CodeEnum> enums = GetEnums("TestClass.cs");    
    bool first = true;

    // Header
    foreach(CodeEnum e in enums)
    {
        if(first)
            first = false;
        else
            Write(",");

        Write(e.Name);
    }
    WriteLine("");

    // Data
    WriteData(enums);
#>
<#+
    private void WriteData(List<CodeEnum> enums)
    {
        WriteData(enums, new string[enums.Count], 0);
    }

    private void WriteData(List<CodeEnum> enums, string[] values, int level)
    {   
        foreach (CodeElement element in enums[level].Children)
        {
            values[level] = element.Name;

            if(level + 1 < enums.Count)
            {
                WriteData(enums, values, level + 1);
            }
            else
            {
                WriteLine(string.Join(",", values));
            }
        }
    }

    private List<CodeEnum> GetEnums(string enumFile)
    {
        ProjectItem projectItem = TransformationContext.FindProjectItem(enumFile);
        FileCodeModel codeModel = projectItem.FileCodeModel;
        return FindEnums(codeModel.CodeElements);
    }

    private List<CodeEnum> FindEnums(CodeElements elements)
    {
        List<CodeEnum> enums = new List<CodeEnum>();

        FindEnums(elements, enums);

        return enums.Count == 0
            ? null
            : enums;
    }

    private void FindEnums(CodeElements elements, List<CodeEnum> enums)
    {
        foreach (CodeElement element in elements)
        {
            if (element is CodeEnum)
                enums.Add((CodeEnum)element);

            FindEnums(element.Children, enums);
        }
    }
#>
0 голосов
/ 04 июня 2010

Как уже упоминалось @hemp, вы можете использовать внешний тест, который генерирует все перестановки ваших перечислений. Класс на http://www.codeproject.com/KB/recipes/Combinatorics.aspx выглядит довольно интересно.

Однако тестирование всех возможных комбинаций - это просто проверка работоспособности? Для меня это запах кода, и я бы искал крайние случаи вместо того, чтобы затормозить время выполнения теста с запуском перестановок. Просто мысль. :)

...