目录
介绍
背景
使用代码
兴趣点
要测试REST API控制器的数据模型的验证,仅创建控制器类的实例并调用预期的方法是不可行的。它只是不测试验证,而只是跳过验证。我们需要一个真正的REST调用,但是我们需要从xUnit测试中获得它,而不是在手动启动应用程序时进行手动调用。两个软件包(Refit和IntegrationFixture)可以为我们提供帮助,本文介绍了如何做。
介绍使用xUnit,实际上很容易调用方法并验证响应。但是,方法调用并不总是反映实际情况。例如,在执行REST API调用以触发控制器方法时,可能首先要进行一些验证。该验证可能不是您的应用程序本身的一部分,而是由诸如[Required]的验证属性设置的。本文介绍了如何轻松解决该问题。您不需要太多的样板代码,只需要正确的软件包和技巧即可。
背景如果您对.NET Core的xUnit和REST API开发有一定的经验,它将帮助您理解此处给出的解释。
使用代码这是我们要测试的方法。它根据名字和姓氏返回全名。中间名也可以包括在内,但是是可选的。
[HttpPost]
public ActionResult Post([FromBody] Name value)
{
return Ok($"{value.FirstName} {value.MiddleName} {value.LastName}");
}
从逻辑上讲,数据模型也需要实现。
public class Name
{
[Required]
public string FirstName { get; set; }
public string MiddleName { get; set; }
[Required]
public string LastName { get; set; }
}
从上面显示的代码可以清楚地看出,名字和姓氏是必需的。中间名不是。
我们不能只从控制器实例中调用controller方法。这将跳过由验证属性触发的验证。但是,我们可以通过启动并执行REST调用来手动测试应用程序。从逻辑上讲,这很难用xUnit实现,也很难成为CI构建的一部分。解决方法如下:
首先,在使应用程序自托管成为测试的一部分时,我们需要一个Refit接口来进行一次调用。改装可作为NuGet包提供。接口如下所示:
public interface ILogicClient
{
[Post("/api/logic")]
Task Post([Body] Name name);
}
现在,我们需要在测试中以编程方式创建一个实现和实例。为此,我们需要一个新的NuGet软件包,该软件包也支持自托管。该软件包(IntegrationFixture)也可以作为NuGet软件包使用。
[Theory]
[InlineData("Boris","Alexander", "Johnson",
HttpStatusCode.OK, "Boris", "Alexander", "Johnson")]
[InlineData("Boris", "Alexander", null, HttpStatusCode.BadRequest)]
[InlineData(null, "Alexander", "Johnson", HttpStatusCode.BadRequest)]
[InlineData("Boris", "Alexander", "", HttpStatusCode.BadRequest)]
[InlineData("", "Alexander", "Johnson", HttpStatusCode.BadRequest)]
public async Task NamesTest(string firstName, string middleName,
string lastName, HttpStatusCode expectedStatusCode, params string[] responseContains)
{
using (var fixture =
new RefitFixture(RestService.For))
{
var refitClient = fixture.GetRefitClient();
var response = await refitClient.Post(new Name
{
FirstName = firstName,
MiddleName = middleName,
LastName = lastName,
});
var statusCode = response.StatusCode;
Assert.Equal(expectedStatusCode, statusCode);
var content = response.Content;
foreach (var expectedResponse in responseContains)
{
Assert.Contains(expectedResponse, content);
}
}
}
从上面的代码可以清楚地看到,我们有几个测试用例。根据可用的名称,返回特定的状态码。这就是验证属性应该触发的内容,所以这就是我们要声明的内容。此外,当获得肯定结果时,我们还声明响应的内容。现在问题已解决。在这里RefitFixture至关重要。它知道用于启用应用程序自我托管的Startup类。此外,它也知道用于对自托管应用程序进行REST调用的改装接口ILogicClient。这就解决了我们的问题:我们可以使用xUnit测试验证属性,而无需启动应用程序。本文中的代码可在GitHub上获得。
对我来说,提到的NuGet包中的RefitFixture类确实很有帮助。当我刚开始开发.NET Core应用程序时,我手动执行了应用程序以测试验证。这不再需要。验证和其他类似中间件的事物可以使用xUnit进行测试,就像常规的单元测试一样。