【问题标题】:What should a controller integration test assert控制器集成测试应该断言什么
【发布时间】:2015-06-14 23:30:29
【问题描述】:

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

我的端点也在调用域服务。

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

我对服务返回值感兴趣吗?其实并不是。 我只对端点是否成功触发感兴趣,但我猜应该隔离服务调用。

欢迎任何建议:-)

测试

[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);
}

【问题讨论】:

  • 再次...为什么 2 票接近?

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


【解决方案1】:

在 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 服务正确处理它。

这告诉我的是,我的 Web 服务应该处理预期和异常情况并返回适当的代码:200/404/500。

虽然有些是错误状态,有些是成功状态,但这些结果都没有表明我的 Web 服务有问题 - 它的行为完全符合其应有的状态,这正是我想要测试的。

对 Web 服务的“跨网络”集成测试无法告诉您应用程序的稳健性或正确性 - 或者即使它返回正确的数据或响应代码。

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

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

假设 WebAPI 可以正常工作,并且不需要您再次对其进行测试。专注于测试您的应用程序代码并确保您的 Web 服务能够优雅地处理成功和错误条件。

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

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

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

【讨论】:

  • 你所做的是一个单元测试。但我想做集成测试,请看这里:strathweb.com/2013/12/owin-memory-integration-testing 我想知道当我在 url 栏中输入“api/schoolyears”时(不需要浏览器)我的 Get 方法被触发。这与您的单元测试期望无关。是的,您在我快速破解的 Get 方法中是对的,我总是得到 Code 200。我只捕获那些我期望的异常。当有人忘记插入数据库时​​,我可以记录它,但我不会通过粉红色的用户对话框对其做出反应。我只是让它崩溃。
  • 你现在写了很多,对于单元测试来说都是正确的。但遗憾的是,在我的特殊情况下,这不是我所期望或帮助我的,请参阅我的问题。也许我的测试方法太简单了,它真的说明了为什么这里的集成测试是有意义的。应该涉及更多的基础设施内容,例如设置标头、添加查询参数、有人删除 Http 动词属性 - 您的端点是否仍然被触发? -
  • 好吧,我在质疑您是否真的需要集成测试,以及从中获得什么价值...从您的评论看来,您想测试是否基于某个特定条件触发了正确的路由HTTP Verb 或 QueryString - 这是一个不同的问题,不需要任何形式的集成:strathweb.com/2012/08/testing-routes-in-asp-net-web-api
  • 嗯,我想在集成测试中有很多东西。 (非常普遍...)有趣的是,您还发布了来自strathweb 的链接,该链接实际上是 web api 集成测试的追随者,但您不是。有时原因只是意见。你能告诉我你什么时候做集成测试吗?即使在执行控制器操作之前我有 5 个委托处理程序,我也可以对它们进行单元测试...
  • 同样的问题:stackoverflow.com/questions/11927587/… 非常好的附加示例链接,其中包含我需要如何模拟服务的答案!我不会投票赞成关闭这个重复的线程,所以你会得到积分,我赞成 3 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 2016-07-25
相关资源
最近更新 更多