【问题标题】:Dependent unit tests and returning Task<T> from a unit test依赖单元测试并从单元测试返回 Task<T>
【发布时间】:2021-09-04 07:09:20
【问题描述】:

MSTest 框架如何处理依赖于其他单元测试的单元测试?我正在测试一个 REST API,并花了相当长的时间试图了解大局。在此过程中出现了以下问题:

  1. 我们应该编写调用其他测试方法的测试方法吗?它是否以某种方式违背了 unit 测试的想法?还是应该将单元测试彼此完全隔离?
  2. 如果被隔离,当某个 api 端点需要输入而只能通过调用另一个 API 端点(已经存在测试)来获取时,我们该怎么办?例如端点GetMembers端点需要认证令牌,该令牌只能通过调用Login端点获得。每个端点都有一个单独的测试。从TestGetMembers 调用TestLogin 方法公平吗,还是应该在TestGetMembers 中重复TestLogin 的整个代码(或者为此编写一个函数来共享代码)?
  3. 我应该将登录令牌保存在哪里,因为所有后续测试都需要它。看起来 MSTest 为每个测试方法创建了一个新的测试类实例,所以我的全局变量丢失了。可以声明 static 变量来保存这些值吗?
  4. async 测试呢?我的研究表明async 测试可以返回Task,但不能返回Task&lt;T&gt;。 Visual Studio 测试资源管理器没有列出任何返回 Task&lt;T&gt; 并尝试手动运行它们的测试方法(例如,通过在方法内部右键单击并选择 Run Test)在没有实际运行测试方法的情况下完成。有这样的限制吗?如果是,我如何从异步测试方法返回值,该值将被另一个测试方法使用?

【问题讨论】:

  • 你在测试代表端点的控制器方法吗?
  • @ElConrado:我正在测试 Web api 公开的所有端点。这基本上是对我的数据服务的所有功能的测试(每个端点一个服务方法)。
  • 听起来更像是集成测试。
  • @rene:这不是 mstest 框架应该处理的?
  • 测试代码(单元或集成)遵循与常规代码相同的规则。如果您在单一测试方法中遵循 Arrange、Act、Assert 理念,则不会复制/粘贴代码,而是重构(提取方法、移动到基类等)。

标签: c# unit-testing mstest


【解决方案1】:

我主要回答你的第一个问题。如果您能够模拟服务器行为,您可以测试端点方法,但在我看来,它是过度工程。单元测试是为测试单元逻辑而设计的。在良好的设计中,您将逻辑注入控制器(例如作为服务、外观或其他架构对象),并且您需要测试注入的方法。在下面的代码中,我不测试 GetById 控制器方法,而是测试 _facade.MyMethod()。如果您的控制器方法中有更复杂的逻辑,则应将其移至另一层。如果您要测试外观逻辑,如我在示例中所写,您可以省略身份验证,因为您不需要令牌,尽管它也取决于您的授权机制。

public class MyExampleObjectController : ControllerBase
{
    private readonly IExampleObjectFacade _facade;

    public MyExampleObjectController(IExampleObjectFacade facade)
    {
        _facade = facade;
    }

    [HttpGet]
    [Authorize]
    [ProducesResponseType(200)]
    [ProducesResponseType(404)]
    public async Task<IActionResult> GetById(Guid id,
    CancellationToken cancellationToken = default)
    {
        var item = await _facade.MyMethod(id, cancellationToken);
        if (item == null)
        {
            return NotFound();
        }
        return Ok(item);
    }
}

【讨论】:

  • 试图理解。我的数据服务是一个非常薄的层,它只是使用 RestSharp 调用 api 端点,对返回的数据进行反序列化并将其返回给调用者。所以我的数据服务中有一个Login函数调用/login端点,一个GetMembers函数调用/members端点等等。现在我的单元测试正在测试这些功能中的每一个(每个功能一个测试),但有些测试依赖于其他测试。例如GetMemberDetails 需要成员 id,只能通过调用 GetMembers 来获取,所以这就是混乱开始的地方。
  • 好的,所以您的问题与使用相关数据相关。此数据由您的服务通过 API 端点下载。在这种情况下,我建议模拟内部 enpoint,因此您的单元测试调用 /login 但接收模拟数据。您正在考虑使用起订量吗?
  • mmm... 我听说过 Moq 并且可能了解它的作用,但测试应该检查服务本身(以及实时 api 端点),而不是一些模拟。想法是在我的班级中简单地运行所有测试,以确保服务能够正确处理实时服务器返回的数据并为更高层提供数据。
  • 来自实时 api 端点的数据是否会改变您的测试结果?
  • 是的,如果有一些服务器端的变化,比如api参数或返回类型,因为我无法控制服务器端。这些测试只是为我提供一键式解决方案以快速确定所有端点是否都接受并返回预期内容的一种方式。
猜你喜欢
  • 1970-01-01
  • 2021-05-27
  • 2021-06-19
  • 2012-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多