控制器集成测试应该断言什么

时间:2015-06-14 23:30:29

标签: c# asp.net-web-api integration-testing asp.net-web-api2

在web api端点上进行集成测试我应该把重点放在断言上吗?

我的终端也在调用域名服务。

我应该嘲笑那项服务吗?使用当前不可能的代码,因为我需要实例化控制器以传递模拟服务。

我对服务返回值感兴趣吗?其实并不是。 我只对端点被成功触发感兴趣但是我应该隔离服务电话。

欢迎任何建议: - )

TEST

[TestClass]
public class SchoolyearControllerTests
{
    private TestServer _server;

    [TestInitialize]
    public void FixtureInit()
    {
        _server = TestServer.Create<Startup>();
    }

    [TestCleanup]
    public void FixtureDispose()
    {
        _server.Dispose();
    }

    [TestMethod]
    public void Get()
    {
        var response = _server.HttpClient.GetAsync(_server.BaseAddress + "/api/schoolyears").Result;
        var result = response.Content.ReadAsAsync<IEnumerable<SchoolyearDTO>>().GetAwaiter().GetResult();
        Assert.AreEqual(response.StatusCode, HttpStatusCode.OK);
    }
}

要测试的行动

[HttpGet]
public async Task<IHttpActionResult> Get()
{
    var schoolyears = await service.GetSchoolyears();
    return Ok(schoolyears);
}

1 个答案:

答案 0 :(得分:4)

在Web服务上进行集成测试的麻烦在于它并没有告诉你很多关于这个问题的信息 - 或者即使它确实存在问题,如果存在问题,它也不会告诉你问题出在哪里所在。它会成功还是失败。所以在这方面你得到了200响应代码或500响应代码......但它失败了因为:

  • 服务器无法访问
  • 尝试启动时未启动或失败的Web服务
  • 防火墙阻止网络
  • 未找到数据库记录
  • 存在数据库架构问题,实体框架未启动 正常。

它几乎可以是任何东西 - 结果可能与您的开发机器上的结果不同而不是生产 - 所以它真正告诉您的应用程序是什么?

强大的软件的作用是测试您的产品是否能够正确,优雅和稳健地处理任何这些情况。

我写这样的控制器动作:

   public HttpResponseMessage Get(int id)
    {
        try
        {
            var person = _personRepository.GetById(id);
            var dto = Mapper.Map<PersonDto>(person);
            HttpResponseMessage response = Request.CreateResponse<PersonDto>(HttpStatusCode.OK, dto);
            return response;
        }
        catch (TextFileDataSourceException ex)
        {
            HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.InternalServerError);
            return response;
        }
        catch (DataResourceNotFoundException ex)
        {
            HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            return response;
        }
        catch (FormatException ex)
        {
            HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
            return response;
        }
        catch (Exception ex)
        {
            HttpResponseMessage response = Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
            return response;
        }
    }

try块获取数据,生成dto并返回带有200代码的数据。这里处理了几个错误条件,但没有一个表明我的Web服务本身有问题,有些(404错误)甚至没有表明应用程序出现问题 - 如果我的应用程序找不到,我预测NotFoundException和404记录 - 如果发生这种情况我的应用程序在这种情况下工作。

因此,如果出现任何这些错误情况,那不是因为Web服务存在问题,而且不一定是应用程序的问题。但我可以测试我的Web服务是否正在为这些预期条件返回正确的响应。

此控制器操作的测试如下所示:

    [Test]
    public void CanGetPerson()
    {
        #region Arrange
        var person = new Person
            {
                Id = 1,
                FamilyName = "Rooney",
                GivenName = "Wayne",
                MiddleNames = "Mark",
                DateOfBirth = new DateTime(1985, 10, 24),
                DateOfDeath = null,
                PlaceOfBirth = "Liverpool",
                Height = 1.76m,
                TwitterId = "@WayneRooney"
            };

        Mapper.CreateMap<Person, PersonDto>(); 

        var mockPersonRepository = new Mock<IPersonRepository>();
        mockPersonRepository.Setup(x => x.GetById(1)).Returns(person);

        var controller = new PersonController(mockPersonRepository.Object);

        controller.Request = new HttpRequestMessage(HttpMethod.Get, "1");
        controller.Configuration = new HttpConfiguration(new HttpRouteCollection());
        #endregion

        #region act
        HttpResponseMessage result = controller.Get(1);
        #endregion

        #region assert
        Assert.AreEqual(HttpStatusCode.OK, result.StatusCode);
        #endregion
    }

    [Test]
    public void CanHandlePersonNotExists()
    {
        #region Arrange
        var mockPersonRepository = new Mock<IPersonRepository>();
        mockPersonRepository.Setup(x => x.GetById(1)).Throws<DataResourceNotFoundException>();

        var controller = new PersonController(mockPersonRepository.Object)
            {
                Request = new HttpRequestMessage(HttpMethod.Get, "1"),
                Configuration = new HttpConfiguration(new HttpRouteCollection())
            };

        #endregion

        #region Act
        HttpResponseMessage result = controller.Get(1);
        #endregion

        #region Assert
        Assert.AreEqual(HttpStatusCode.NotFound, result.StatusCode);
        #endregion
    }

    [Test]
    public void CanHandleServerError()
    {
        #region Arrange
        var mockPersonRepository = new Mock<IPersonRepository>();
        mockPersonRepository.Setup(x => x.GetById(1)).Throws<Exception>();

        var controller = new PersonController(mockPersonRepository.Object);
        controller.Request = new HttpRequestMessage(HttpMethod.Get, "1");
        controller.Configuration = new HttpConfiguration(new HttpRouteCollection());
        #endregion

        #region Act
        HttpResponseMessage result = controller.Get(1);
        #endregion

        #region Assert
        Assert.AreEqual(HttpStatusCode.InternalServerError, result.StatusCode);
        #endregion
    }

请注意,我正在引入一个模拟存储库,并让我的模拟存储库触发404和服务器错误的预期异常,并确保Web服务正确处理它。

这告诉我的是,我的网络服务处理预期和特殊情况,并返回相应的代码:200/404/500。

虽然有些是错误状态,有些是成功状态,但这些结果都没有表明我的网络服务存在问题 - 它的行为完全正确,这就是我想测试的内容。

Web服务上的“跨网络”集成测试不会告诉您应用程序的健壮性或正确性 - 或者即使它返回正确的数据或响应代码也是如此。

不要试图重新测试WebAPI ......微软已经为它编写了大量的测试套件 - 数百个测试夹具类,成千上万的测试方法:

https://aspnetwebstack.codeplex.com/SourceControl/latest#test/System.Web.Http.Test/Controllers/ApiControllerTest.cs

假设WebAPI正常工作,并且不需要您再次测试它。专注于测试应用程序代码,并确保Web服务正常处理成功和错误条件。

如果您想检查您的网络服务已连接并可在网络上使用 - 打开浏览器并手动测试;没有必要自动化这个;结果会因环境和外部条件而异。

以相同的方式测试应用程序的每一层,模拟上面的层并测试当前层处理来自上层的每个可能的结果。

您的服务的客户端应用程序应该做同样的事情:模拟Web服务,假装它给了404 - 并检查它是否应该处理它。