当初始化程序具有依赖性时,F#XUnit测试死锁

问题描述 投票:2回答:1

我在netcoreapp2.2 .net核心测试项目中遇到测试问题。

在测试开始之前,我需要获取将在测试之间共享的一些数据。

但是,从命令行运行以下测试时,它将挂起。像这样执行测试:

dotnet test --filter "Test async initialization"

错误的代码如下所示:

let c = new HttpClient (BaseAddress = (Uri "https://swapi.co/api/people/1/"))    

let luke = 
    async {                
        return! c.GetStringAsync "" |> Async.AwaitTask        
    } |> Async.RunSynchronously

[<Fact>]
let ``Test async initialization`` () =  
    Assert.NotNull(luke)

如果我将HttpClient的创建放在luke fetcher中,就像这样:

let luke = 
    let c = new HttpClient (BaseAddress = (Uri "https://swapi.co/api/people/1/"))
    async {                
        return! c.GetStringAsync "" |> Async.AwaitTask        
    } |> Async.RunSynchronously

[<Fact>]
let ``Test async initialization`` () =  
    Assert.NotNull(luke)

这意味着我不能在不同的获取者之间共享相同的HttpClient。

任何人都知道发生了什么,以及如何在多个功能之间共享同一个客户端?

f# xunit
1个回答
2
投票

问题是由于“初始化”代码不是真正的初始化代码引起的。这些只是两个静态字段,仅在请求时才会进行评估。如果您调试单元测试,您将看到cluke仅在执行到达行时执行

Assert.NotNull(luke)

如果您使用像JustDecompile这样的反编译器,您将看到模块的代码放在一个名为Tests$的静态类中,其静态构造函数初始化其自己的cluke属性。 Test async initialization被放置在Tests类中,有自己的cluke属性,委托给Tests$类。

长话排序,在请求luke的值之前,没有任何“初始化”代码运行。我不知道为什么最终会阻止测试,很可能与测试运行器存在冲突。初始化代码在初始化时不运行就足够了。

要使初始化代码运行,可以使用“经典”测试类型:

namespace MyTests


open System
open Xunit
open System.Net.Http
open Xunit.Abstractions

type Tests() =

    static let c = new HttpClient (BaseAddress = (Uri "https://swapi.co/api/people/1/"))    

    static let luke = 
        async {                
            return! c.GetStringAsync "" |> Async.AwaitTask        
        } |> Async.RunSynchronously

    static do 
        //Pity we can't actually print here
        printfn "Even more initialization!"

    [<Fact>]
    let ``Test async initialization`` () =  
        Assert.NotNull(luke)

在这种情况下,静态绑定在任何测试之前执行,因为它们应该,并且代码不会阻塞。此初始化仅发生一次。

对于capture output,测试类构造函数应该接受ITestOutputHelper参数。现在我们有一个测试类很容易做到:

type Tests(output:ITestOutputHelper) =

    ...

    [<Fact>]
    let ``Test async initialization`` () =  
        Assert.NotNull(luke)
        output.WriteLine "It worked!"

每次测试初始化​​应该在do块中:

type Tests(output:ITestOutputHelper) =

    do
      output.WriteLine "This prints before each test"
© www.soinside.com 2019 - 2024. All rights reserved.