์ ๋ค๋ฆญ์ ์ฌ์ฉํ์ฌ ๋ ์ ์ค๊ณํ ์ ์๋ ๋ช ๊ฐ์ง ํ
์คํธ ์ฌ๋ก๋ฅผ ์์
์ค์
๋๋ค. ๋ค์ํ ์ ํ์ ์กฐํฉ์ผ๋ก 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)
Return ๋ฉ์๋์ ์ ์ฌํ TestCaseData.GenericsArgs(params Type[] generics)์ ๊ฐ์ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ด๋ป์ต๋๊น?
๊ทธ๊ฒ๋ ํจ๊ณผ๊ฐ ์์ ์ ์์ต๋๋ค. @nunit/framework-team, ์ด ์ฃผ์ ๊ฐ ํฅ๋ฏธ๋กญ๋ค๊ณ ์๊ฐํ๋ ์ฌ๋์ด ์์ต๋๊น?
์ด ๋ฌธ์ ๋ ์์ด๋์ด/๋์์ธ/ํ ๋ก ์ผ๋ก ํ์๋์ง๋ง ๋ช ๋ ๋์ ๊ธฐ์ฌํ์ง ์์์ผ๋ฏ๋ก ๋ซ์ต๋๋ค. ๋๊ตฌ๋ ์ง ์ด ์์ด๋์ด๋ฅผ ์์ ํ๋ ๋ฐ ๊ด์ฌ์ด ์๋ ๊ฒฝ์ฐ ๊ด์ฌ์ ๊ฒ์ํ๋ฉด ํ์์ ์ฌ๊ฐ๋ฅผ ๊ณ ๋ คํ ๊ฒ์ ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๊ทธ๊ฒ๋ ํจ๊ณผ๊ฐ ์์ ์ ์์ต๋๋ค. @nunit/framework-team, ์ด ์ฃผ์ ๊ฐ ํฅ๋ฏธ๋กญ๋ค๊ณ ์๊ฐํ๋ ์ฌ๋์ด ์์ต๋๊น?