Доступ к NUnit Test Name в TestCaseSource
У меня есть серия тестов, в которых я хочу использовать те же данные тестовых данных для кучи разных тестов.
например:
[Test, TestCaseSource("TestData")]
public void Test1(Foo foo)
{
// test 1
}
[Test, TestCaseSource("TestData")]
public void Test2(Foo foo)
{
// test 2
}
private static IEnumerable TestData()
{
TestCaseData data;
data = new TestCaseData(new Foo("aaa"));
yield return data;
data = new TestCaseData(new Foo("bbb"));
yield return data;
}
Это приводит к серии тестов, которые сообщают так:
Namespace.That.Is.Very.Long.TestClass.Test1(Namespace.That.Is.Very.Long.Foo)
Namespace.That.Is.Very.Long.TestClass.Test1(Namespace.That.Is.Very.Long.Foo)
Namespace.That.Is.Very.Long.TestClass.Test2(Namespace.That.Is.Very.Long.Foo)
Namespace.That.Is.Very.Long.TestClass.Test2(Namespace.That.Is.Very.Long.Foo)
... который не имеет большого значения, если вы не знаете, что "foo" не удалось.
Если как предложено в этом вопросе SO, я задал имя следующим образом:
data = new TestCaseData(new Foo("aaa"));
data.SetName("foo=aaa");
yield return data;
... тогда все мои тесты выглядят так:
foo=aaa
foo=bbb
foo=aaa
foo=bbb
Итак, я пытаюсь выяснить, как получить текущее имя метода тестирования. Это выглядело бы как как описано в этом другом вопросе SO, через TestContext.
Однако, хотя TestContext.Current.Test существует, все свойства (например, Name) вызывают исключение NullReferenceException при попытке получить к ним доступ.
Есть ли другой способ достижения этой цели предоставления более полезной информации в имени теста?
Ответы
Ответ 1
Свойство TestName
имеет поддержку в NUnit 3 для форматирования строк.
Здесь пример использования:
private static IEnumerable TestData()
{
TestCaseData data;
data = new TestCaseData(new Foo("aaa"))
.SetName("case 1 {m}");
yield return data;
data = new TestCaseData(new Foo("bbb"));
yield return data;
}
Сгенерирует следующий вывод:
![введите описание изображения здесь]()
Как вы можете видеть имена тестов, первый случай содержит пользовательский префикс + имя метода.
Используйте эту ссылку для получения дополнительной информации о возможности создания строк NUnit.
Для этого действия сохраняются 2 класса NUnitTestCaseBuilder (строка 83) и TestNameGenerator
метод .GetDisplayName()
.
Ответ 2
После долгих поисковых запросов я нашел решение, которое было намного проще, чем те, которые были выше:
первый. В тестовом случае я добавил еще один параметр: string testName:
[Test, TestCaseSource("TestData")]
public void Test1(string testName, Foo foo)
{
// test 1
}
[Test, TestCaseSource("TestData")]
public void Test2(String testName, Foo foo)
{
// test 2
}
второй. в TestCaseData я добавил еще один параметр, который показывает уникальное свойство объекта Foo, например. имя
private static IEnumerable TestData()
{
TestCaseData data;
Foo data1 = new Foo("aaa");
data = new TestCaseData(data1.name, data1);
yield return data;
Foo data2 = new Foo("bbb");
data = new TestCaseData(data2.name, data2);
yield return data;
}
В бегуне NUnit результат отображается следующим образом:
Namespace.That.Is.Very.Long.TestClass.Test1("aaa", Namespace.That.Is.Very.Long.Foo)
Namespace.That.Is.Very.Long.TestClass.Test1("bbb", Namespace.That.Is.Very.Long.Foo)
Это делает тесты отдельными в окне вывода, в то время как я все еще могу видеть, какой именно тест выполняется.
Ответ 3
Это не идеальный ответ, но лучшим решением, которое я нашел до сих пор, является то, что я создаю оболочку для эмитента TestData, который передается как TestCaseSource.
[Test, TestCaseSource("TestData_Test1")]
public void Test1(Foo foo)
{
// test 1
}
[Test, TestCaseSource("TestData_Test2")]
public void Test2(Foo foo)
{
// test 2
}
private static IEnumerable TestData_Test1()
{
return TestData_Base("Test1");
}
private static IEnumerable TestData_Test2()
{
return TestData_Base("Test2");
}
private static IEnumerable TestData_Base(string testName)
{
TestCaseData data;
data = new TestCaseData(new Foo("aaa"));
data.SetName(string.Format("{0}(Foo=aaa)", testName));
yield return data;
data = new TestCaseData(new Foo("bbb"));
data.SetName(string.Format("{0}(Foo=bbb)", testName));
yield return data;
}
Это означает, что мои тесты теперь испускаются из NCrunch, TeamCity и т.д. как
Test1(Foo=aaa)
Test1(Foo=bbb)
Test2(Foo=aaa)
Test2(Foo=bbb)
Это, по крайней мере, лучше, чем полностью бесполезное значение по умолчанию.
Ответ 4
Хорошо, если вам повезло использовать .NET 4.5, вы можете использовать атрибут [CallerMemberName] в последнем аргументе конструктора нового атрибута TestCaseSourceEx, расширяющего TestCaseSource, который даст вам имя метода тестирования внутри конструктора атрибутов,
Здесь рабочий пример:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class TestCaseSourceEx : TestCaseSourceAttribute
{
public TestCaseSourceEx(Type sourceType, string sourceName, [CallerMemberName] string methodName = null)
: base(sourceType, sourceName)
{
}
public TestCaseSourceEx(string sourceName, [CallerMemberName] string methodName = null)
: base(sourceName)
{
}
}
[TestFixture]
public class SampleTests
{
public IEnumerable List = new[] { new string[] { "test-username", "test-password" } };
[Test, TestCaseSourceEx("List")]
public void SampleTests_LoginTest(string username, string password)
{
}
}
Ответ 5
Как насчет этого?
[TestCase("aaa")]
[TestCase("bbb")]
public void MainTest(string str)
{
Assert.DoesNotThrow(()=> Test1(new Foo(str)));
Assert.DoesNotThrow(()=> Test2(new Foo(str)));
}
public void Test1(Foo foo)
{
// test 1
}
public void Test2(Foo foo)
{
// test 2
}
UPD:
[TestCase("aaa")]
[TestCase("bbb")]
public void Test1(string str)
{
var foo = new Foo(str);
// rest of the test
}
[TestCase("aaa")]
[TestCase("bbb")]
public void Test2(string str)
{
var foo = new Foo(str);
// rest of the test
}