рдореИрдВ рдХреБрдЫ рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЛрдВ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬрд┐рдиреНрд╣реЗрдВ рдЬреЗрдирд░рд┐рдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдмреЗрд╣рддрд░ рддрд░реАрдХреЗ рд╕реЗ рдбрд┐рдЬрд╛рдЗрди рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдореИрдВ рдХрдИ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдВрдпреЛрдЬрдиреЛрдВ рдХреЗ рд╕рд╛рде 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
рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд┐рдпрд╛ рд╣реИред
рдХреНрдпрд╛ рдпрд╣ рдпреЛрдЧрджрд╛рди рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдЦреБрд▓рд╛ рд╣реИ? рдкреАрдЖрд░ рдмрдирд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдореИрдВ рдбрд┐рдЬрд╛рдЗрди рдХреЛ рд╕реНрдкрд╖реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред
рдХреНрдпрд╛ рдпрд╣ рдпреЛрдЧрджрд╛рди рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдЦреБрд▓рд╛ рд╣реИ? рдкреАрдЖрд░ рдмрдирд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдореИрдВ рдбрд┐рдЬрд╛рдЗрди рдХреЛ рд╕реНрдкрд╖реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВред
рдмрд╛рддрдЪреАрдд рд╢реБрд░реВ рдХрд░рдиреЗ рдФрд░ рдорджрдж рдХреА рдкреЗрд╢рдХрд╢ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХрд╛ рдмрд╣реБрдд-рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рджред рдЖрдкрдХреЗ рдкреАрдЖрд░ рдмрдирд╛рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рд╣рдо рдбрд┐рдЬрд╝рд╛рдЗрди рдХреЛ рд╕реНрдкрд╖реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред =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[] Generic) рдЬреИрд╕реА рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрдпрд╛ред
рдпрд╣ рднреА рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИред @ рдиреВрдирд┐рдЯ/рдлреНрд░реЗрдорд╡рд░реНрдХ-рдЯреАрдо, рдХрд┐рд╕реА рдФрд░ рдХреЛ рдпрд╣ рд╡рд┐рд╖рдп рджрд┐рд▓рдЪрд╕реНрдк рд▓рдЧрддрд╛ рд╣реИ?
рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдПрдХ рд╡рд┐рдЪрд╛рд░/рдбрд┐рдЬрд╝рд╛рдЗрди/рдЪрд░реНрдЪрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдЪрд┐рд╣реНрдирд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд░реНрд╖реЛрдВ рдореЗрдВ рдпреЛрдЧрджрд╛рди рдирд╣реАрдВ рд╣реБрдЖ рд╣реИ рдЗрд╕рд▓рд┐рдП рдореИрдВ рдмрдВрдж рдХрд░ рд░рд╣рд╛ рд╣реВрдВред рдЕрдЧрд░ рдХрд┐рд╕реА рдХреЛ рдЗрд╕ рд╡рд┐рдЪрд╛рд░ рдкрд░ рдХрд╛рдо рдХрд░рдиреЗ рдореЗрдВ рджрд┐рд▓рдЪрд╕реНрдкреА рд╣реИ, рддреЛ рдЕрдкрдиреА рд░реБрдЪрд┐ рдкреЛрд╕реНрдЯ рдХрд░реЗрдВ рдФрд░ рдЯреАрдо рдлрд┐рд░ рд╕реЗ рдЦреЛрд▓рдиреЗ рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░реЗрдЧреАред
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдпрд╣ рднреА рдХрд╛рдо рдХрд░ рд╕рдХрддрд╛ рд╣реИред @ рдиреВрдирд┐рдЯ/рдлреНрд░реЗрдорд╡рд░реНрдХ-рдЯреАрдо, рдХрд┐рд╕реА рдФрд░ рдХреЛ рдпрд╣ рд╡рд┐рд╖рдп рджрд┐рд▓рдЪрд╕реНрдк рд▓рдЧрддрд╛ рд╣реИ?