当被测类型覆盖 ToString 时无法 运行 TestCaseSource 测试
Unable to run TestCaseSource tests when the type under test overrides ToString
首先,让我介绍 F# 中的测试设置(在 NUnit 之上使用 FsUnit):
type SimpleRecord = { A: int; B: int }
override x.ToString() = x.A.ToString()
[<TestFixture>]
type ``Simple Test Cases``() =
static member SimpleDataSource =
[|
[|{ A = 1; B = 2} ,3|]
|]
[<TestCaseSource("SimpleDataSource")>]
member x.``SimpleTest`` (testData: SimpleRecord * int) =
let data, expected = testData
data.A + data.B
|> should equal expected
此测试将 运行 并按预期通过。但是,更改 ToString
覆盖以包含对 Guid.ToString()
的调用将阻止测试 运行:
type SimpleRecord = { A: int; B: int }
override x.ToString() = x.A.ToString() + Guid.NewGuid().ToString()
进行上述更改后,测试仍会出现在测试资源管理器中,但不会 运行。即使右键单击它并选择 运行 Selected Tests 也不会执行测试。没有报告构建错误。
我也尝试过使用 DateTime.ToString()
而不是 Guid.ToString()
,但这也拒绝 运行:
type SimpleRecord = { A: int; B: int }
override x.ToString() = x.A.ToString() + DateTime.Now.ToString()
为什么在 ToString
覆盖中调用 Guid.ToString()
或 DateTime.ToString()
覆盖正在测试的类型导致测试不是 运行ning?
Charlie Poole 提供了根本原因的解释:
When tests are run using the NUnit console or gui runners, they are
first loaded (discovered) and then executed. When running under the
adapter, the tests are loaded twice, once in the discovery phase and
again at the beginning of the execution phase. This is a result of the
way the VS Test Window works: discovery and execution are run in
separate processes created by VS.
This doesn't cause a problem in most cases. The tests are loaded
twice, which means the code for creating any test data is run twice.
Usually, the same data is generated both times.
However, when using random data, it's known that different data will
be generated in each phase. Tests that are shown in the initial
discovery seem to disappear while "unknown" tests are run.
In your case, the guid is generated twice. The first one is used as
part of the name of the test, consequently, that test disappears in
the execution phase.
下面是一个演示解决方法的示例:
type ProblemRecord = { A: int; B: int }
override x.ToString() = Guid.NewGuid().ToString()
[<TestFixture>]
type ``Test Cases``() =
// Using TestCaseData and explicitly setting a name will resolve the problem
member x.SolutionDataSource =
[
TestCaseData(({ A = 1; B = 2} : ProblemRecord), 3)
.SetName("Workaround")
]
// This test case will be run by Test Explorer
[<TestCaseSource("SolutionDataSource")>]
member x.``SolutionTest`` (data: ProblemRecord, expected: int) =
data.A + data.B
|> should equal expected
首先,让我介绍 F# 中的测试设置(在 NUnit 之上使用 FsUnit):
type SimpleRecord = { A: int; B: int }
override x.ToString() = x.A.ToString()
[<TestFixture>]
type ``Simple Test Cases``() =
static member SimpleDataSource =
[|
[|{ A = 1; B = 2} ,3|]
|]
[<TestCaseSource("SimpleDataSource")>]
member x.``SimpleTest`` (testData: SimpleRecord * int) =
let data, expected = testData
data.A + data.B
|> should equal expected
此测试将 运行 并按预期通过。但是,更改 ToString
覆盖以包含对 Guid.ToString()
的调用将阻止测试 运行:
type SimpleRecord = { A: int; B: int }
override x.ToString() = x.A.ToString() + Guid.NewGuid().ToString()
进行上述更改后,测试仍会出现在测试资源管理器中,但不会 运行。即使右键单击它并选择 运行 Selected Tests 也不会执行测试。没有报告构建错误。
我也尝试过使用 DateTime.ToString()
而不是 Guid.ToString()
,但这也拒绝 运行:
type SimpleRecord = { A: int; B: int }
override x.ToString() = x.A.ToString() + DateTime.Now.ToString()
为什么在 ToString
覆盖中调用 Guid.ToString()
或 DateTime.ToString()
覆盖正在测试的类型导致测试不是 运行ning?
Charlie Poole 提供了根本原因的解释:
When tests are run using the NUnit console or gui runners, they are first loaded (discovered) and then executed. When running under the adapter, the tests are loaded twice, once in the discovery phase and again at the beginning of the execution phase. This is a result of the way the VS Test Window works: discovery and execution are run in separate processes created by VS.
This doesn't cause a problem in most cases. The tests are loaded twice, which means the code for creating any test data is run twice. Usually, the same data is generated both times.
However, when using random data, it's known that different data will be generated in each phase. Tests that are shown in the initial discovery seem to disappear while "unknown" tests are run.
In your case, the guid is generated twice. The first one is used as part of the name of the test, consequently, that test disappears in the execution phase.
下面是一个演示解决方法的示例:
type ProblemRecord = { A: int; B: int }
override x.ToString() = Guid.NewGuid().ToString()
[<TestFixture>]
type ``Test Cases``() =
// Using TestCaseData and explicitly setting a name will resolve the problem
member x.SolutionDataSource =
[
TestCaseData(({ A = 1; B = 2} : ProblemRecord), 3)
.SetName("Workaround")
]
// This test case will be run by Test Explorer
[<TestCaseSource("SolutionDataSource")>]
member x.``SolutionTest`` (data: ProblemRecord, expected: int) =
data.A + data.B
|> should equal expected