如何使用 XUnit 2.0 和 FSharp 样式测试捕获输出

How to capture output with XUnit 2.0 and FSharp style tests

通常我用 F# 编写单元测试

open Swensen.Unquote
open Xunit

module MyTests =

    [<Fact>]
    let ``SomeFunction should return 10`` () =
        let a = SomeFunction()
        test <@ a = 10 @>


    [<Fact>]
    let ``SomeOtherFunction should return 11`` () =
        let a = SomeFunction()
        test <@ a = 11 @>

如果我想从 xunit 登录到控制台(根据 http://xunit.github.io/docs/capturing-output.html ),需要编写一个构造函数,该构造函数采用 ITestOutputHelper 然后使用它代替Console.WriteLine 和家人。

using Xunit;
using Xunit.Abstractions;

public class MyTestClass
{
    private readonly ITestOutputHelper output;

    public MyTestClass(ITestOutputHelper output)
    {
        this.output = output;
    }

    [Fact]
    public void MyTest()
    {
        var temp = "my class!";
        output.WriteLine("This is output from {0}", temp);
    }
}

然而 fsharp 模块是静态的 类 并且测试是静态方法。没有构造函数来注入输出助手。

有没有办法访问当前测试的当前输出助手。我知道我可以将我的 fsharp 测试重写为非静态 类 但这是不希望的。

查看 XUnit 源代码后。

https://github.com/xunit/xunit/blob/e64f566b75f93cd3cec27f950759d82832bfe44b/src/xunit.execution/Sdk/Frameworks/Runners/TestClassRunner.cs#L90

我很确定这是一个被忽视的案例。没有将 helper 注入静态 类。

如果 xUnit 没有任何替代机制来注入参数,那么我想唯一的选择是将测试定义为 F# 对象类型中的方法。我也更喜欢使用 let 将测试编写为函数,但以下简单对象类型看起来还不错:

open Swensen.Unquote
open Xunit
open Xunit.Abstractions

type MyTests(output:ITestOutputHelper) =

    [<Fact>]
    member __.``SomeFunction should return 10`` () =
        let a = SomeFunction()
        output.WriteLine("Some function returned {0}", a)
        test <@ a = 10 @>

如果 xUnit 支持一些其他选项,那就太好了 - 我怀疑他们可能会接受建议,如果它不会太尴尬(也许使用方法参数?)

但除非 xUnit 添加对某些其他方法的支持,否则我认为您将需要使用 F# 对象和方法。

现在这个解决方案似乎也适用于 let 绑定:

module Tests

open System
open System.Text.Json
open System.Text.Json.Serialization
open Xunit
open Xunit.Abstractions
open Core.DomainModel.OnboardingModel

type SerializationTests(output: ITestOutputHelper) =
    
    let options = JsonSerializerOptions()
    do
        JsonFSharpConverter(
            unionEncoding = JsonUnionEncoding.InternalTag,
            unionTagName = "type",
            allowOverride = true
        )
        |> options.Converters.Add

    [<Fact>]
    let ``CanSerializeDiscriminatedUnion using Fsharp.SystemTextJson`` () =
        let onboardingStep = InformName "test"
        let serialization = JsonSerializer.Serialize(onboardingStep, options)
        output.WriteLine serialization

执行此命令时,结果将显示在控制台上:

dotnet test  --logger:"console;verbosity=detailed"

结果:

[xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v2.4.3+1b45f5407b (64-bit .NET 6.0.1)
[xUnit.net 00:00:00.44]   Discovering: Core.DomainModel.Tests
[xUnit.net 00:00:00.47]   Discovered:  Core.DomainModel.Tests
[xUnit.net 00:00:00.47]   Starting:    Core.DomainModel.Tests
[xUnit.net 00:00:00.58]   Finished:    Core.DomainModel.Tests
  Passed Tests+SerializationTests.CanSerializeDiscriminatedUnion using Fsharp.SystemTextJson [58 ms]
  Standard Output Messages:
 ["InformName","test"]



Test Run Successful.
Total tests: 1
     Passed: 1
 Total time: 1.1842 Seconds