unit-testing - 当被测类型覆盖 ToString 时,无法运行 TestCaseSource 测试

标签 unit-testing f# nunit fsunit testcasesource

首先,让我介绍 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()

经过上述更改,测试仍然出现在测试资源管理器中,但不会运行。即使右键单击它并选择运行选定的测试也不会执行测试。没有报告任何构建错误。

我还尝试使用 DateTime.ToString() 而不是 Guid.ToString(),但这也拒绝运行:

type SimpleRecord = { A: int; B: int } 
                    override x.ToString() = x.A.ToString() + DateTime.Now.ToString()

为什么会在正在测试的类型的 ToString 覆盖中调用 Guid.ToString()DateTime.ToString() 导致测试未运行?

最佳答案

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

关于unit-testing - 当被测类型覆盖 ToString 时,无法运行 TestCaseSource 测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32014436/

相关文章:

f# - 使用 FParsec 我将如何解析 : line ending in newline <|> a line ending with eof

c# - 如何对此进行单元测试?具有大量数据库调用的大 foreach

v3 中缺少 Nunit.core 和 Nunit.util

android - fragment 单元测试 : launchFragment throws ClassCastException

unit-testing - 单元测试/TDD 的有用设计模式?

multithreading - 如何限制在 F# 中为异步 Seq.map 操作创建的线程数?

f# - 延迟接口(interface)方法的执行?

c# - 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

java - 您需要在单元测试中使用 Theme.AppCompat 主题 -->

ruby-on-rails - Rails Controller 测试 - 验证错误不会引发 HTTP 错误响应