我在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。
任何人都知道发生了什么,以及如何在多个功能之间共享同一个客户端?
问题是由于“初始化”代码不是真正的初始化代码引起的。这些只是两个静态字段,仅在请求时才会进行评估。如果您调试单元测试,您将看到c
和luke
仅在执行到达行时执行
Assert.NotNull(luke)
如果您使用像JustDecompile这样的反编译器,您将看到模块的代码放在一个名为Tests$
的静态类中,其静态构造函数初始化其自己的c
和luke
属性。 Test async initialization
被放置在Tests
类中,有自己的c
和luke
属性,委托给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"