我在集成测试中使用NSubstitute,方法是使用模拟程序包装真实的实现,如下所示:
var realRepository = container.Get<IRepository>();
var proxyRepository = Substitute.For<IRepository>();
proxyRepository
.When(repo => repo.InsertValueForEntity(Arg.Any<int>(), Arg.Any<ValueForEntity>())
.Do(callInfo => realRepository
.InsertValueForEntity((int)callInfo.Args()[0], (ValueForEntity)callInfo.Args()[1]));
proxyRepository
.GetValueForEntity(Arg.Any<int>())
.Returns(callInfo => realRepository
.GetValueForEntity((int)callInfo.Args()[0]));
// assume these parameters are defined elsewhere
var factory = new EntityFactory(mock1, realDependency, mock2, proxyRepository);
var entity = factory.CreateEntity(/* args */); // <-- this is where proxyRepository.GetValueForEntity() should be called
proxyRepository.Received().InsertValueForEntity(entity.Id, dummyValue);
proxyRepository.Received().GetValueForEntity(Arg.Is(entity.Id));
Assert.That(entity.Value, Is.EqualTo(dummyValue));
对此我感到奇怪的是,我使用了.When().Do()
这样的另一项测试,并且效果很好。实际上,看来InsertValueForEntity
的配置在这里也适用。但是,GetValueForEntity
的配置不有效,我不明白为什么。我在lambda上设置了一个断点,但它从未命中。
我在这里缺少关于替补的一些棘手的东西吗?
答案 0 :(得分:1)
示例代码似乎没有任何明显的问题,因此我猜测这是一些未显示的代码的问题。是否可以发布说明问题的可运行版本?我还建议将NSubstitute.Analyzers添加到您的项目中,因为它可以帮助检测有时导致令人困惑的测试行为的问题。
这是一个简化的版本,可以演示一切正常工作。如果有可能进行修改以重现该问题,那将非常有帮助!
首先,一些支持类型:
public interface IRepository {
ValueForEntity GetValueForEntity(int v);
void InsertValueForEntity(int v, ValueForEntity valueForEntity);
}
public class RealRepository : IRepository {
private readonly IDictionary<int, ValueForEntity> data = new Dictionary<int, ValueForEntity>();
public ValueForEntity GetValueForEntity(int v) => data[v];
public void InsertValueForEntity(int v, ValueForEntity valueForEntity) => data[v] = valueForEntity;
}
public class ValueForEntity {
public int Id { get; set; }
}
然后大致近似于要测试的主题:
public class EntityFactory {
private readonly IRepository repo;
public EntityFactory(IRepository repo) => this.repo = repo;
public ValueForEntity CreateEntity(int id) {
repo.InsertValueForEntity(id, new ValueForEntity { Id = id });
return repo.GetValueForEntity(id);
}
}
最后,这是发布的测试的通过版本(我拥有XUnit而不是NUnit,因此相应地更改了assert和test属性):
[Fact]
public void Example() {
var realRepository = new RealRepository();
var proxyRepository = Substitute.For<IRepository>();
proxyRepository
.When(repo => repo.InsertValueForEntity(Arg.Any<int>(), Arg.Any<ValueForEntity>()))
.Do(callInfo => realRepository
.InsertValueForEntity((int)callInfo.Args()[0], (ValueForEntity)callInfo.Args()[1]));
proxyRepository
.GetValueForEntity(Arg.Any<int>())
.Returns(callInfo => realRepository
.GetValueForEntity((int)callInfo.Args()[0]));
var factory = new EntityFactory(proxyRepository);
var entity = factory.CreateEntity(42 /* args */);
proxyRepository.Received().InsertValueForEntity(entity.Id, Arg.Any<ValueForEntity>());
proxyRepository.Received().GetValueForEntity(Arg.Is(entity.Id));
Assert.Equal(42, entity.Id);
}
我知道类型不完全匹配,但是希望您可以使用此工作示例来找出造成灯具问题的主要区别。
顺便说一句,如果只使用realRepository
,是否值得在这里使用替代品?