单元测试扩展方法,试了一下,这是对的,还是绕过房子?

Unit testing extension methods, had a go, is this right, or gone around the houses?

我有我的 POCO 库,我有实现名为 IEntityDelete 的接口的实体。

界面很简单,看起来像这样

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

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

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/

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

首先创建了我的包装器接口

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

创建一个实现此接口的class

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

将此接口注入我的服务构造函数

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

更改我的服务方法调用以像这样使用包装器

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

    return _context.SaveChangesAsync();
}

已解决 有人告诉我,这太过分了,我只能检查 属性 是否已更改。鉴于此,我仍在使用我的扩展方法并将我的单元测试更新为此。

[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 调用后实体属性是否发生变化就足够了。

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

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