我正在尝试创建一个单元测试来模拟我的 API 被很多人同时调用。
我的单元测试中有这段代码:
var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
var id = i; // must assign to new variable inside for loop
var t = Task.Run(async () =>
{
response = await Client.GetAsync("/api/test2?id=" + id);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
});
tasks.Add(t);
}
await Task.WhenAll(tasks);
然后在我的控制器中我放入一个
Thread.Sleep
。我预计所有电话都会或多或少同时拨打并结束于
Thread.Sleep
电话。
但是 API 调用似乎是一个接一个地进行的。
我测试并行 API 调用的原因是因为我想测试使用 SQLite 时数据存储库的死锁问题,这种情况仅在超过 1 个用户同时使用我的网站时才会发生。
我从来没有能够模拟这个,我想我应该创建一个单元测试,但我现在拥有的代码似乎没有并行执行调用。
我对 Thread.Sleep 调用的计划是在 Controller 方法中放置几个调用,以确保所有请求同时在某些代码块之间结束。
我是否需要在 Web 服务器上设置最大并行请求数或其他什么,或者我是否做了一些明显错误的事情?
更新1: 我忘了提及我使用
await Task.Delay(1000);
和许多类似的替代方案得到了相同的结果。
不确定是否清楚,但这都是在使用 NUnit 的单元测试中运行的。
“Web 服务器”和客户端是这样创建的:
var builder = new WebHostBuilder().UseStartup<TStartup>();
Server = new TestServer(builder);
Client = Server.CreateClient();
您可以使用
Task.Delay(time in milliseconds)
。 Thread.Sleep
不会释放线程,并且在等待结果时无法处理其他任务。
.NET 中的
HttpClient
类默认限制对同一服务器的两个并发请求,我认为这可能会导致本例中的问题。通常,可以通过创建新的 HttpClientHandler
并将其用作构造函数中的参数来覆盖此限制:
new HttpClient(new HttpClientHandler
{
MaxConnectionsPerServer = 100
})
但是因为客户端是使用
TestServer
方法创建的,所以事情变得有点复杂。您可以尝试更改 ServicePointManager.DefaultConnectionLimit
属性,如下所示,但我不确定这是否适用于 TestServer
:
System.Net.ServicePointManager.DefaultConnectionLimit = 100;
话虽如此,我认为使用单元测试进行负载测试并不是一个好方法,建议研究特定于负载测试的工具。
我的测试发现了问题。
这不是测试服务器或客户端代码,而是数据库代码。
在我的控制器中,我正在启动一个 NHibernate 事务,这会阻塞请求,因为它会锁定正在更新的表。
这是正确的,所以我必须稍微更改我的代码才能不自动启动交易。而是将其留给调用代码来管理。