Подтвердить что ты не робот

Есть ли среда С# unit test, которая поддерживает произвольные выражения, а не ограниченный набор adhoc-методов?

В основном NUnit, xUnit, MbUnit, MsTest и т.п. имеют методы, аналогичные следующим:

Assert.IsGreater(a,b)
//or, a little more discoverable
Assert.That(a, Is.GreaterThan(b))

Однако существует ограниченное число таких операторов сравнения; и они дублируют языки операторов бесполезно. Когда я хочу что-нибудь даже немного сложное, например...

Assert.That(a.SequenceEquals(b))

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

С#, однако, хорошо интегрируется с произвольными выражениями, поэтому должен быть возможно иметь метод со следующей сигнатурой:

void That(Expression<Func<bool>> expr);

Такой метод может использоваться как для выполнения теста (т.е. подтверждения утверждения), так и для обеспечения менее непрозрачной диагностики в случае отказа теста; в конце концов, выражение может быть представлено псевдокоду, чтобы указать, какое выражение не удалось; и с некоторым усилием вы могли бы даже разумно оценить ошибочные выражения, чтобы дать некоторое представление о значении подвыражений.

Например:

Assert.That(()=> a == b);//could inspect expression and print a and b
Assert.That(()=> a < b && b < c);
//could mention the values of "a<b" and "b<c" and/or list the values of a, b, and c.

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

Существует ли такая вещь?

Изменить: После попытки (и симпатии!) Power Assert я закончил переопределять его, чтобы устранить несколько ограничений. Мой вариант этого опубликован как ExpressionToCode; см. мой ответ ниже для получения списка улучшений.

4b9b3361

Ответ 1

(Оригинальный плакат здесь)

Мне нравится PowerAssert.NET простой синтаксис и сообщения, но у С#, который он создает, много проблем. В частности, он не поддерживает несколько функций выражения, и он не добавляет круглых скобок, если это необходимо по приоритету/ассоциативности операторов. После исправления нескольких ошибок (и сообщения их автору) я обнаружил, что было бы проще исправить другой подход и переопределить его с нуля.

Использование похоже:

PAssert.That(()=>
    Enumerable.Range(0,1000).ToDictionary(i=>"n"+i)["n3"].ToString()
    == (3.5).ToString()
);

Выходы:

PAssert.That failed for:

Enumerable.Range(0, 1000).ToDictionary(i => "n" + (object)i)["n3"].ToString() == 3.5.ToString()
             |                 |                            |         |        |        |
             |                 |                            |         |        |        "3.5"
             |                 |                            |         |        false
             |                 |                            |         "3"
             |                 |                            3
             |                 {[n0, 0], [n1, 1], [n2, 2], [n3, 3], [n4, 4], [n5, 5], [n6, 6], [n7, 7], [n8, 8], [n9, 9], ...}
             {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...}

Улучшения над PowerAssert.NET:

  • Поддерживает доступ к статическому полю и свойствам.
  • Поддерживает больше операторов, таких как логическое и побитовое отрицание.
  • Распознает использование индексатора С# (например, dict["mykey"]==3)
  • Добавляет скобки, где требуется приоритет и ассоциативность операторов (например, () => x - (a - b) + x * (a + b) правильно регенерируется)
  • Генерирует действительные числовые и другие константные литералы, включая экраны и суффиксы, соответствующие типу выражения (например, 1m + (decimal)Math.Sqrt(1.41))
  • Поддерживает синтаксический сахар С# для инициализаторов объектов, инициализаторов элементов, инициализаторов списков, методов расширения, среди прочего.
  • Использует те же правила, что и Visual Studio по умолчанию.
  • Поддержка вложенных Lambdas
  • Развертывает экземпляры типичного типа в обычный С#; например Func<int, bool>
  • Поддерживает несколько конструкций дерева выражений, еще не используемых встроенными выражениями С# 4.0.

Результирующий проект (с модульными тестами) размещен в коде google под именем ExpressionToCode - я надеюсь, что это полезно для других.

Ответ 2

Проверьте библиотеку PowerAssert (пример ниже):

PAssert.IsTrue(() => x + 5 == d.Month * y);


System.Exception : IsTrue failed, expression was:

x + 5 == d.Month * y
| |   |  | |     | |
| |   |  | |     | 6
| |   |  | |     18
| |   |  | 3
| |   |  01/03/2010 00:00:00
| |   False
| 16
11

http://powerassert.codeplex.com/

Ответ 3

http://satisfyr.codeplex.com/

Использует лямбда-выражения точно так, как вы описали. Вы даже не принимаете двоичную зависимость, просто добавьте один исходный файл, соответствующий вашей инфраструктуре unit test.

Ответ 4

На самом деле существует очень веская причина, что NUnit предоставляет собственный DSL, а не обычные выражения С#. Это значит, что NUnit должен работать с любым языком .NET используя тот же синтаксис. Это не значит, что у нас не может быть лямбда, просто мы никогда не будем полагаются исключительно на какую-либо особенность языка.

Многие из приведенных идей будут работать, и многие сторонние программные решения могут быть включены в NUnit при условии, что их авторы захотят их предложить. Конечно, многие люди предпочитают, чтобы их решения были раздельными и что ОК тоже. Но поговорите со своими любимыми авторами, если вы хотите, чтобы они более тесно сотрудничали с NUnit.

В NUnit 2.5 вы можете использовать PredicateConstraint, который принимает лямбда в качестве аргумента. Однако синтаксис является немного ограничивающим. Ключевое слово Matches будет работать в середине выражения, поэтому вы можете написать...

Assert.That(someActual, Not.Matches(someLambda);

но делать это без необходимости...

Assert.That(someActual, новый PredicateConstraint (someLambda));

И, конечно, ни то, ни другое не так чисто, как предлагаемый синтаксис.

Все, кто интересуется этой проблемой, могут присоединиться к нам на nunit-обсуждении, где обсуждения о том, что должно быть в NUnit, фактически приводят к действию!

Charlie

Ответ 5

Конус (https://github.com/drunkcod/cone) - это дополнение NUnit, которое работает с 2.5.5 и 2.5.7 (другие версии только перекомпилируются), который дает вам эту возможность наряду с несколькими другими замечательными функциями.

Ответ 6

Никто из тех, кого я знаю, но я думаю, что это может быть добавлено в предстоящий список желаний NUnit 3.

Некоторая работа с этой целью, сделанная в #TestEx http://sharptestex.codeplex.com/, рассматривается для включения, но вы можете добавить проект/проблему для более общий подход, который вы задаете.

https://blueprints.launchpad.net/nunit-3.0

https://bugs.launchpad.net/nunit-3.0

Ответ 7

В инфраструктуре Visual Studio 2010 unit test есть класс CollectionAssert, который полезен.

Он также предоставляет Assert.IsTrue(bool) для общих случаев, которые вы создаете самостоятельно, но не используете выражения,