0

我想使用 NSubstitute 创建一个间谍,但在经过大量谷歌搜索和阅读文档后无法找到。

这个想法是用一个覆盖的方法来替代,我可以像往常一样使用模拟来监控收到的呼叫等。但是如何使用 NSubstitute 来实现呢?

我宁愿既不放松protected也不放松abstract修饰符。

这是我想做的事情:

[Test]
public void Items_Add_shouldCall_ItemAddedMethod()
{
    var sut = Substitute.For<ItemsRepository>();
    // how to configure???
    sut.Items.Add(Substitute.For<IItem>());

    sut.Received().ItemAdded();  // currently cannot do this

// ...

public abstract class ItemsRepository
{
    public ObservableCollection<IItem> Items { get; set; } 
        = new ObservableCollection<IItem>();

    // ...

    protected abstract void ItemAdded();
}
4

1 回答 1

2

NSubstitute API 依赖于调用一个方法来配置它Returns或检查Received()调用,这意味着对于标准使用,我们只能处理可以通过公共 API(不包括protectedprivate成员)调用的调用。abstract您的问题部分没有问题;可以将 NSubstitute 与可访问的abstract成员一起使用。

尽管 C# 在设计上阻止我们直接与protected成员交互,但 NSubstitute 仍然记录对这些成员的调用。我们可以使用“非官方” .ReceivedCalls()扩展来检查这些:

public abstract class ItemsRepository {
    public virtual void Add(int i) { ItemAdded(); }
    protected abstract void ItemAdded();
}

public class Fixture {
    [Fact]
    public void CheckProtectedCall() {
        var sub = Substitute.For<ItemsRepository>();
        sub.When(x => x.Add(Arg.Any<int>())).CallBase();

        sub.Add(42);

        var called = sub.ReceivedCalls().Select(x => x.GetMethodInfo().Name);

        Assert.Contains("ItemAdded", called);
    }
}

其他选项包括创建派生类(正如@Nkosi 指出的那样),或使成员internal代替protected并使用InternalsVisibleTo以使成员可访问您的测试代码(如果您这样做,我建议安装NSubstitute.Analyzer以帮助确保已配置正确)。

于 2019-04-01T21:16:39.110 回答