Я работаю над некоторыми тестовыми примерами, которые могут быть лучше разработаны с использованием дженериков. Я пытаюсь использовать TestCaseSource
со многими различными комбинациями типов.
Проблема, с которой я сталкиваюсь, заключается в использовании отражения в моих тестах для вызова общего метода тестирования, который я использую для проверки объекта.
[TestFixture]
public class SomeTests
{
public static IEnumerable<TestCaseData> TestCases()
{
yield return
new TestCaseData(
typeof(Foo),
typeof(Bar),
Generator.Foo,
Assertions.Foo);
yield return
new TestCaseData(
typeof(Bar),
typeof(Foo),
Generator.Bar,
Assertions.Bar);
}
[TestCaseSource(nameof(TestCases))]
public void CheckSomeTypes(
Type sourceType,
Type destinationType,
TSource source,
Action<object, object> assert)
{
GetType()
.GetMethod(nameof(CheckSomeTypesImpl), BindingFlags.Public | BindingFlags.Instance)
.MakeGenericType(new[] { sourceType, destinationType })
.Invoke(this, new object[] { source, assert });
}
public void CheckSomeTypesImpl<TSource, TDestination>(
TSource source,
Action<TSource, TDestination> assert)
{
var destination = Mapper.Map<TSource, TDestination>(source);
// Assert are equiviliant
assert(source, destination);
}
}
Тем не менее, я считаю, что следующий дизайн может добавить ценность в этом случае:
[TestFixture]
public class SomeTests
{
public static IEnumerable<TestCaseData> TestCases()
{
yield return
new TestCaseData(
typeof(Foo),
typeof(Bar),
Generator.Foo,
Assertions.Foo);
yield return
new TestCaseData(
typeof(Bar),
typeof(Foo),
Generator.Bar,
Assertions.Bar);
}
[TestCaseSource(nameof(TestCases))]
public void CheckSomeTypes<TSource, TDestination>(
TSource source,
Action<TSource, TDestination> assert)
{
var destination = Mapper.Map<TSource, TDestination>(source);
// Assert are equiviliant
assert(source, destination);
}
}
public class Foo
{
public string Qux { get; set; }
}
public class Bar
{
public string Qux { get; set; }
}
public static class Generator
{
public static Foo Foo =>
new Foo { Qux = "TestTestTest" };
public static Bar Bar =>
new Foo { Bar = "AnotherAnotherAnother" };
}
public static class Mapper
{
// Generic mapper function
public static TDestination Map<TSource, TDestination>(TSource source)
{
if (typeof(TSource) == typeof(Foo))
{
return Map((Foo) source);
}
if (typeof(TSource) == typeof(Bar))
{
return Map((Bar) source);
}
throw new NotImplementedException($"No mapping for {typeof(TSource).FullName}.");
}
public static Foo Map(Bar bar)
{
return new Foo { Qux = bar.Qux };
}
public static Bar Map(Foo foo)
{
return new Bar { Qux = foo.Qux };
}
}
public static class Assertions
{
public static Action<Foo, Bar> Foo =>
(foo, bar) => Assert.AreEqual(foo.Qux, bar.Qux);
public static Action<Bar, Foo> Bar =>
(bar, foo) => Assert.AreEqual(bar.Qux, foo.Qux);
}
Я сделал локальное расширение TestCaseSourceAttribute
для поддержки этого.
Это что-то открытое для вклада? Я хочу сначала уточнить дизайн, прежде чем создавать PR.
Это что-то открытое для вклада? Я хочу сначала уточнить дизайн, прежде чем создавать PR.
Большое спасибо за начало разговора и предложение помощи. Мы также хотим уточнить дизайн, прежде чем создавать PR. =D Скорее всего, скоро он будет открыт для пожертвований!
То же самое, но для TestCaseAttribute
, а не для TestCaseSourceAttribute
: https://github.com/nunit/nunit/issues/1215
Только вывод: https://github.com/nunit/nunit/issues/150
Сегодня мне уже приходится писать неоптимальный код, поэтому я абсолютно этого хочу.
Как вы думаете, есть ли в конструкторе TestCaseData
способ более визуально отличать значения Type
, которые заполняют общие параметры метода, от значений Type
, которые заполняют обычные параметры метода?
Для удобства обнаружения: как насчет new TestCaseData<T1, T2>(ordinaryArg1, ordinaryArg2)?
Или это, что позволило бы нам избежать объявления N новых классов TestCaseData
:
TestCaseData.Create<T1, T2>(ordinaryArg1, ordinaryArg2, ordinaryArg3)
Как насчет использования такого метода, как TestCaseData.GenericsArgs(params Type[] generics), аналогичного методу Returns.
Это тоже может сработать. @nunit/framework-team, кому еще интересна эта тема?
Эта проблема помечена как идея/дизайн/обсуждение, но в ней не было комментариев в течение многих лет, поэтому я закрываю. Если кто-то заинтересован в работе над этой идеей, сообщите о своем интересе, и команда рассмотрит возможность повторного открытия.
Самый полезный комментарий
Это тоже может сработать. @nunit/framework-team, кому еще интересна эта тема?