NUnit 3.0 TestCase const настраиваемые аргументы объекта

Я написал класс SomeObject, и я хочу определить экземпляр const этого объекта для сохранения/повторного использования в моих TestCase s. Как мне переписать код ниже для достижения такого поведения?

[TestFixture]
public class SomeObjectTests
{
    private const SomeObject item0 = new SomeObject(0.0); // doesn't work

    [TestCase(item0, ExpectedResult = 0.0)]
    public double TestSomeObjectValue(SomeObject so)
    {
        return so.Value;
    }

    [TestCase(item0, ExpectedResult = "0.0")]
    public string TestSomeObjectValueString(SomeObject so)
    {
        return so.ValueString;
    }
}

Появляется следующее сообщение об ошибке:

Поле const ссылочного типа, отличное от строки, может быть инициализировано только нулевым значением.

Ответ 1

спецификация языка С#, §10.3 говорит (внимание мое):

Если требуется символическое имя для постоянного значения, но когда тип этого значения не разрешен в объявлении константы или когда значение не может быть вычислено во время компиляции константным выражением, a Поле readonly (Раздел 10.4.2) может использоваться вместо.


Раздражающе, это усугубляется тем фактом, что атрибуты также имеют определенные ограничения - см. спецификацию языка С#, §17.2 (опять же, ):

Выражение E является выражением атрибута-аргумента, если все следующие утверждения верны:

  • Тип E - это тип параметра атрибута (раздел 17.1.3).

  • Во время компиляции значение E можно решить одним из следующих:

    • Постоянное значение.

    • Объект System.Type.

    • Одномерный массив атрибутов-аргументов-выражений.

Где §17.1.3: "Типы параметров атрибутов" говорит 1:

Типы позиционных и именованных параметров для класса атрибута ограничены типами атрибутных параметров, которые:

  • Один из следующих типов: bool, byte, char, double, float, int, long, short, string.
  • Тип object.
  • Тип System.Type.
  • Тип перечисления, если он имеет общедоступную доступность, и типы, в которых он вложен (если есть), также имеют общедоступную доступность (§17.2).
  • Одномерные массивы вышеуказанных типов.

1: цитируемый текст относится к более старой версии спецификации С# - в версии С# 5.0, упоминаются четыре дополнительных типа: sbyte, uint, ulong и ushort.


Другими словами, лучшее, что вы можете сделать, это что-то вроде:

[TestFixture]
public class SomeObjectTests {

    private static readonly SomeObject item0 = new SomeObject(0.0);

    private static SomeObject getObject(string key) {
        if ( key == "item0" )
            return item0;

        throw new ArgumentException("Unknown key");
    }

    [TestCase("item0", ExpectedResult = 0.0)]
    public double TestSomeObjectValue(string key) {
        SomeObject so = getObject(key);
        return so.Value;
    }

    [TestCase("item0", ExpectedResult = "0.0")]
    public string TestSomeObjectValueString(string key) {
        SomeObject so = getObject(key);
        return so.ValueString;
    }
}

Таким образом, аргументы атрибутов являются константой времени компиляции, а метод getObject может обрабатывать получение экземпляра SomeObject.

Ответ 2

Лучшим способом добиться того, что вы пытаетесь сделать, является использование TestCaseSource. В вашем случае:

[TestFixture]
public class SomeObjectTests
{
    [TestCaseSource(typeof(TestSomeObject),"TestCasesValue")]
    public double TestSomeObjectValue(SomeObject so)
    {
        return so.Value;
    }

    [TestCaseSource(typeof(TestSomeObject),"TestCasesValueString")]
    public string TestSomeObjectValueString(SomeObject so)
    {
        return so.ValueString;
    }
}

public class TestSomeObject
{
  public static IEnumerable TestCasesValue
  {
    get
    {
        yield return new TestCaseData( new SomeObject(0.0) ).Returns( 0.0 );
        yield return new TestCaseData( new SomeObject(1.0) ).Returns( 1.0 );
    }
  }

  public static IEnumerable TestCasesValueString
  {
    get
    {
        yield return new TestCaseData( new SomeObject(0.0) ).Returns( "0.0" );
        yield return new TestCaseData( new SomeObject(1.0) ).Returns( "1.0" );
    }
  }
}

Ответ 3

  • Просто удалите константу. Это будет приватная переменная для каждого экземпляра
  • Сделайте это статичным, и это будет одноэлемент для класса.
  • Заменить const с помощью readonly. Это будет означать, что это не что-то, что не должно быть запущено.