c# - 单元测试扩展方法,尝试一下,这是正确的,还是绕着房子走?

标签 c# .net unit-testing mocking moq

我有 POCO 库,并且有实现名为 IEntityDelete 的接口(interface)的实体。

界面非常简单,看起来像这样

public interface IEntityDelete 
{
    bool IsDeleted { get; set; }
}

所以我有一个实现这个接口(interface)的实体,同样非常简单,看起来像这样

public class MyEntity() : IEntityDelete
{
    public bool IsDeleted { get; set; }
}

我有一个扩展方法,我创建了这样的

public static void MarkAsDeleted(this IEntityDelete entity)
{
    entity.IsDeleted = true;
}

然后我需要检查这个方法是否在我的单元测试中的一个服务方法中被调用。服务方法非常基本,看起来像这样。

public Task<int> DeleteByFlagAsync(MyEntity entity)
{
    entity.MarkAsDeleted();

    return _context.SaveChangesAsync();
}

显然,如果不使用 Microsoft 的 Moles 框架,您无法轻松测试扩展方法,但我不想要另一个依赖项。

我做了一些谷歌搜索,发现了 2 篇关于此问题的文章,以及如何解决它,并且想知道这是否正确,或者我是否做了一些愚蠢的事情。

我在哪里找到的两篇文章

http://adventuresdotnet.blogspot.co.uk/2011/03/mocking-static-methods-for-unit-testing.html http://blogs.clariusconsulting.net/kzu/how-to-mock-extension-methods/

他们建议使用一个非静态的包装类,所以我最终得到了这个。

首先创建我的包装器界面

public interface IEntityDeleteWrapper 
{
    void MarkAsDeleted(IEntityDelete entity);
}

创建一个实现此接口(interface)的类

public class EntityDeleteWrapper : IEntityDeleteWrapper
{
    public void MarkAsDeleted(IEntityDelete entity)
    {
        entity.IsDeleted = true;
        entity.DeletedDate = DateTime.Now;
        entity.DeletedByUserId = 546372819;
    }
}

将此接口(interface)注入(inject)到我的服务构造函数中

public MyService(IEntityDeleteWrapper deleteWrapper)
{
    _deleteWrapper = deleteWrapper;
}

更改我的服务方法调用以使用包装器,如下所示

public Task<int> DeleteByFlagAsync(MyEntity entity)
{
    _deleteWrapper.MarkAsDeleted(entity);

    return _context.SaveChangesAsync();
}

已解决 正如我被告知的那样,这太远了,我只能检查属性(property)是否发生了变化。鉴于此,我仍在使用我的扩展方法,并将我的单元测试更新为此。

[TestMethod]
public void should_mark_entity_as_deleted()
{
    // arrange
    var entity = new Attachment
    {
        IsDeleted = false
    };

    // act
    var result = _service.DeleteByFlagAsync(entity).Result;

    // assert
    Assert.AreEqual(true, entity.IsDeleted);
    _context.Verify(e => e.SaveChangesAsync(), Times.Once);
}

最佳答案

你太过分了。您的测试应该验证可观察到的状态更改,而不是验证更改的方式。否则你会让你的测试变得非常脆弱,更不用说你添加了相当不必要的额外层。在 DeleteByFlagAsync 调用后检查实体属性是否发生更改就足够了。

当然,当删除变得更加复杂时,引入依赖关系来委托(delegate)此任务是有意义的。但接下来,出现了几个问题:

  • DeleteByFlagAsync 的范围是什么?调用两个依赖项?
  • 测试它是否实用?
  • ...或者也许对所述依赖项进行测试就足够了(因为这是实际标记删除将发生的地方)?

关于c# - 单元测试扩展方法,尝试一下,这是正确的,还是绕着房子走?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31072335/

相关文章:

c# - 这应该被 mock 还是被打断?

c# - 通过索引获取对象的属性值

c# - Linq 加入 - 重复

c# - 使用资源图像作为 RDLC 参数中的值

c# - 在 Unity 中使用 Google Cardboard 进行运动

c# - 如何在 .Net S3 SDK 中按名称获取存储桶?

c++ - Google Mock 中的双重免费

java - 如何使用 Mockito 部分模拟 HttpServletRequest

c# - WPF:一排长度相等的 ToggleButtons?

c# - 获取客户端机器的IP地址