Как поместить новый List‹int› {1} в NUNIT TestCase?

У меня есть метод:

public static int Add(List<int> numbers)
    {
        if (numbers == null || numbers.Count == 0)
            return 0;

        if (numbers.Count == 1)
            return numbers[0];


        throw new NotImplementedException();
    }

Вот мой тест против него, но он не любит new List<int> {1} в TestCase:

    [TestCase(new List<int>{1}, 1)]
    public void Add_WithOneNumber_ReturnsNumber(List<int> numbers)
    {

        var result = CalculatorLibrary.CalculatorFunctions.Add(numbers);

        Assert.AreEqual(1, result);
    }

Это дает мне ошибку:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

Должен ли я сделать это так:

    [Test]
    public void Add_WithOneNumber_ReturnsNumber()
    {

        var result = CalculatorLibrary.CalculatorFunctions.Add(new List<int>{7});


        Assert.AreEqual(7, result);

        var result2 = CalculatorLibrary.CalculatorFunctions.Add(new List<int> {3});

        Assert.AreEqual(4,result2);
    }

person xaisoft    schedule 20.10.2013    source источник
comment
вы не сможете использовать непостоянное выражение в TestCase   -  person Yurii Hohan    schedule 20.10.2013
comment
@YuriiHohan - Является ли мой единственный вариант новым тестом, который я опубликовал?   -  person xaisoft    schedule 20.10.2013
comment
Вы можете использовать здесь TestCaseSource вместо TestCase nunit.org/index.php? p=testCaseSource&r=2.5   -  person Preston Guillot    schedule 20.10.2013


Ответы (8)


Существует один вариант использования атрибута TestCaseSource. Здесь я привожу тест без подтверждения с двумя случаями, чтобы посмотреть, как он работает:

[TestFixture]
public class TestClass
{
    private static readonly object[] _sourceLists = 
    {
        new object[] {new List<int> {1}},   //case 1
        new object[] {new List<int> {1, 2}} //case 2
    };

    [TestCaseSource("_sourceLists")]
    public void Test(List<int> list)
    {
        foreach (var item in list)
            Console.WriteLine(item);
    }
}

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

Дополнительная информация: https://github.com/nunit/docs/wiki/TestCaseSource-Attribute< /а>

person Yurii Hohan    schedule 20.10.2013
comment
Можете ли вы пояснить свой последний комментарий примером? И можно ли на самом деле вызвать другой тест из другого теста или это плохая практика? - person xaisoft; 20.10.2013
comment
Кстати, это сработало, но я согласен, что это немного странно. Я, вероятно, предпочел бы более краткие и аккуратные тесты. - person xaisoft; 20.10.2013
comment
Я не понимаю ценности создания массива списков private в классе только для ссылки на них через атрибут. Не пытаюсь показаться грубым, просто не понимаю, чем это лучше, чем просто отсутствие параметров в методе Test() и генерация списка в самом тестовом методе. Используется ли этот list повторно в других методах тестирования? Если да, то не будет ли метод типа Setup() более полезным или нет? - person Karl Anderson; 22.10.2013
comment
Это не лучше, что я утверждаю в ответе, это просто способ сделать это, который позволяет библиотека. - person Yurii Hohan; 22.10.2013
comment
_sourceLists должен быть общедоступным, а не частным. - person Keith; 30.06.2014
comment
@Кит, почему ты так говоришь? Он отлично работает с закрытыми _sourceLists. - person namford; 24.08.2017
comment
Обновление для вашего комментария, используйте: private static readonly object[] _Data = {new object[] {new List‹int› {0}, test}, new object[] {new List‹int› {0, 5}, test это}, }; [Тест, TestCaseSource (имя (_Данные))] - person zquanghoangz; 11.10.2018
comment
для списка я бы использовал свой ответ вместо этого. Но этот ответ отлично подходит для использования других объектов в TestCases! - person Blechdose; 25.01.2020

Мое решение проще, я просто использую params. Я надеюсь, что это работает для вас!

[TestCase(1, 1)]
[TestCase(10, 5, 1, 4)]
[TestCase(25, 3, 5, 5, 12)]
public void Linq_Add_ShouldSumAllTheNumbers(int expected, params int[] numbers)
{
    var result = CalculatorLibrary.CalculatorFunctions.Add(numbers);
    Assert.AreEqual(expected, result);
}
person Jaider    schedule 08.12.2015
comment
Это не отвечает на вопрос. Вы используете примитивы, которые являются постоянными. Попробуйте это с чем угодно, кроме постоянной времени компиляции. - person Timothy Gonzalez; 29.12.2016

Улучшите код для ответа @Yurii Hohan:

private  static readonly object[] _Data =
        {
            new object[] {new List<int> {0}, "test"},
            new object[] {new List<int> {0, 5}, "test this"},
        };

[Test, TestCaseSource(nameof(_Data))]

Надеюсь, это поможет.

person zquanghoangz    schedule 11.10.2018

Я часто использую строки и синтаксический анализ, так как они хорошо отображаются в тестраннере. Образец:

[TestCase("1, 2")]
[TestCase("1, 2, 3")]
public void WithStrings(string listString)
{
    var list = listString.Split(',')
                         .Select(int.Parse)
                         .ToList();
    ...
}

Выглядит так в раннере Resharper:

введите здесь описание изображения

person Johan Larsson    schedule 21.05.2016

используйте массив в качестве параметра new [] {1, 2} для тестовых случаев и преобразуйте его в список внутри тестового метода numbers.ToList().

using System.Linq
...

[TestCase(new [] {1}, 1)]
[TestCase(new [] {1, 2}, 3)]
[TestCase(new [] {1, 2, 3}, 6)]
public void Return_sum_of_numbers(int[] numbers, int expectedSum)
{
    var sum = CalculatorLibrary.CalculatorFunctions.Add(numbers.ToList());

    Assert.AreEqual(expectedSum, sum );
    // much cooler with FluentAssertions nuget:
    // sum.Should.Be(expectedSum);
}
person Blechdose    schedule 14.04.2019

Вы можете использовать это:

[TestCase(new []{1,2,3})]
public void Add_WithOneNumber_ReturnsNumber(int[] numbers)
person jecaestevez    schedule 18.10.2018
comment
Это не список, это массив. ОП должен был бы преобразовать это в список. - person LarryBud; 04.12.2018

Вы не можете использовать объекты, только константы времени компиляции в атрибутах данных. Чтобы избежать использования отражения, которое я считаю крайне нечитаемым и совсем не подходящим для теста, предназначенного для максимально четкого формального описания поведения, вот что я делаю:

    [Test]
    public void Test_Case_One()
    {
        AssertCurrency(INPUT, EXPECTED);
    }

    [Test]
    public void Test_Case_Two()
    {
        AssertCurrency(INPUT, EXPECTED);
    }

    private void AssertScenario(int input, int expected)
    {
        Assert.AreEqual(expected, input);
    }

Это еще несколько строк, но это только потому, что мне нужен четкий тестовый вывод. Вы могли бы так же легко поместить их в один [Тест], если вы ищете что-то более лаконичное.

person Timothy Gonzalez    schedule 29.12.2016

Вместо этого просто создайте список внутри метода, например:

public void Add_WithOneNumber_ReturnsNumber()
{
    var result = CalculatorLibrary.CalculatorFunctions.Add(new List<int>{1});

    Assert.AreEqual(1, result);
}
person Karl Anderson    schedule 20.10.2013
comment
Означает ли это, что я должен иметь отдельный тест для 3 и 7 и не могу использовать TestCase? - person xaisoft; 20.10.2013
comment
Если 3 и 7 тестируют разные вещи, то да, вам понадобятся разные тестовые случаи для каждого. Если это всего лишь два значения, которые проходят один и тот же тест, то нет. - person Karl Anderson; 20.10.2013
comment
Как я могу включить 3 и 7 в свой тест? Единственный способ, которым я могу думать, - это создать экземпляр списка для каждого числа и вызвать метод добавления, поэтому в основном мой тест работает как TestCase. У меня это правильно? - person xaisoft; 20.10.2013
comment
Является ли мой единственный вариант новым тестом, который я опубликовал? - person xaisoft; 20.10.2013