InlineData를 활용한 기본 예제
가장 간단한 형태의 매개변수화 테스트는 정수형 변수를 사용하며, 데이터는 리스트 형태로 제공됩니다:
[<Theory>]
[<InlineData(0)>]
[<InlineData(1)>]
member _.``생산 테스트 확장``(position:int) =
let testData = [
{production= ["";"s"];dot= 0;backwards= [];forwards= ["s"];dotmax= false;isKernel= true};
{production= ["";"s"];dot= 1;backwards= ["s"];forwards= [];dotmax= true;isKernel= true}]
let item = testData.[position]
let result = {production= item.production;dot= item.dot}
Should.equal result.backwards item.backwards
Should.equal result.forwards item.forwards
Should.equal result.dotmax item.dotmax
Should.equal result.isKernel item.isKernel
다중 매개변수 처리
open Xunit
open Xunit.Abstractions
type ParameterTests(output:ITestOutputHelper) =
[<Theory>]
[<InlineData(1, 42, 43)>]
[<InlineData(1, 2, 3)>]
member _.``덧셈 검증 테스트``(first: int, second: int, expected: int) =
let sum = first + second
Assert.Equal(expected, sum)
테스트 메서드의 매개변수 개수는 InlineData 속성의 인자 수와 일치해야 하며, 그렇지 않으면 테스트 탐색기에서 일부 테스트 클래스가 누락될 수 있습니다.
InlineData의 제약사항은 리터럴 상수만 사용할 수 있다는 점입니다. 이는 속성 매개변수가 컴파일 시간에 상수로 결정되어야 하기 때문입니다.
ClassData 방식
ClassData는 FSharp.xUnit 네임스페이스의 ClassDataBase를 상속받아 사용합니다:
open FSharp.xUnit
type TestDataSet() =
inherit ClassDataBase([
[| 3; 4 |];
[| 32; 42 |]
])
type ClassDataExample(output:ITestOutputHelper) =
[<Theory>]
[<ClassData(typeof<TestDataSet>)>]
member _.comparisonTest (val1 : int, val2 : int) =
Assert.NotEqual(val1, val2)
MemberData 활용
xUnit에서 가장 일반적인 접근법은 MemberData를 직접 사용하는 것입니다. 서로 다른 타입의 매개변수를 전달하려면 튜플을 사용해야 하며, FSharp.Reflection 네임스페이스를 효과적으로 활용할 수 있습니다.
동일 타입 내 멤버 참조 시 멤버 이름을 지정합니다:
type DataProviderExample(output:ITestOutputHelper) =
static member testData =
[
[|"John";""|],"John"
[|"Jane";""|],"Jane"
]
|> Seq.map FSharpValue.GetTupleFields
[<Theory>]
[<MemberData(nameof(DataProviderExample.testData))>]
member _.``문자열 배열 테스트``(input:string[], expected) =
let actual = input.[0]
Assert.Equal(actual, expected)
다른 타입의 데이터 참조 시 MemberType 매개변수를 사용합니다:
open FSharp.Reflection
type ExternalData() =
static member SampleData =
[
"최소 소수는?", 2, true
"인간이 걸어야 할 길은?", 41, false
]
|> Seq.map FSharpValue.GetTupleFields
type MemberDataUsage(output:ITestOutputHelper) =
[<Theory; MemberData("SampleData", MemberType=typeof<ExternalData>)>]
member _.questionTest(question, answer, expected) =
let validate (q:string) ans =
q.Split(" ").Length = ans
Assert.Equal(validate question answer, expected)
고급 활용 패턴
복잡한 데이터 타입을 처리하기 위해 사전을 활용하여 xUnit이 지원하지 않는 타입을 우회할 수 있습니다. 사전의 키를 인라인 데이터 매개변수로 사용하고, 테스트 함수에서 필요한 추가 데이터는 키를 통해 조회합니다:
type ElementUnificationTest(output:ITestOutputHelper) =
static let testData = [
"<br/>",[{index= 0;length= 5;value= TagSelfClosing("br",[])}]
"<p><br></br></p>",[{index= 0;length= 3;value= TagStart("p",[])};{index= 3;length= 4;value= TagSelfClosing("br",[])};{index= 12;length= 4;value= TagEnd "p"}]
]
static let dataMap = Map.ofList testData
static member keySet =
testData
|> Seq.map (fst>>Array.singleton)
[<Theory;MemberData(nameof ElementUnificationTest.keySet)>]
member _.``자체 종료 태그 처리``(input:string) =
let result =
input
|> SeniorTokenizer.tokenize
|> Seq.choose (HtmlTokenSeniorUtils.unifyVoidElement)
|> Seq.toList
let expected = dataMap.[input]
Should.equal expected result
SingleDataSource를 이용한 최적화
NuGet 패키지 설치:
Install-Package FSharp.xUnit
SingleDataSource 클래스를 활용한 구현 예제:
namespace FSharp.xUnit
open Xunit
open Xunit.Abstractions
open FSharp.xUnit
type DataSourceExample(output:ITestOutputHelper) =
static let dataSource = SingleDataSource[
0,[]
1,[()]
2,[();()]
]
static member keyValues = dataSource.keys
[<Theory>]
[<MemberData(nameof DataSourceExample.keyValues)>]
member _.``단위 리스트 테스트`` (key:int) =
let generated = List.replicate key ()
let expected = dataSource.[key]
Should.equal expected generated
외부 데이터 소스 활용
데이터 소스가 테스트 클래스 외부에 위치할 경우 MemberType 매개변수를 지정해야 합니다:
type ExternalSource() =
static let source = SingleDataSource[
"",{index= 0;length= 15;value= DOCTYPE "HTML"}
]
static member keys = source.keys
static member getItem key = source.[key]
type ConsumerTest(output:ITestOutputHelper) =
[<Theory>]
[<MemberData(nameof ExternalSource.keys, MemberType=typeof<ExternalSource>)>]
member _.``데이터 소스 테스트``(input:string) =
let processed = Consumption.DS 0 input
output.WriteLine(stringify processed)
let expected = ExternalSource.getItem input
Should.equal processed expected