在构造函数中设置响应式扩展代码的模拟时,我遇到了一些先有鸡还是先有蛋的问题。这是被测试的类(以及它所依赖的服务接口(interface)):
class MyViewModel
{
public int Thing { get; set; }
public MyViewModel(IMyService service)
{
service.StreamOfThings.Subscribe(x => Thing = x));
}
public void SomeClickEvent()
{
// Do something with `Thing`
}
}
public interface IMyService
{
IObservable<int> StreamOfThings { get; }
}
为了使测试更容易,我还定义了一个名为 AutoMockData
的自定义属性我可以使用 Moq 通过 AutoFixture 将模拟实例注入(inject)到我的类中:
public class AutoMockDataAttribute : AutoDataAttribute
{
private static IFixture Create() =>
new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
public AutoMockDataAttribute() : base(Create) {}
}
有了这个,我就可以编写我的测试了(使用 NUnit3):
[Test, AutoMockData]
public void Verify_some_behavior(
[Frozen] Mock<IMyService> mockService,
MyViewModel vm)
{
mockService.Setup(x => x.StreamOfThings).Returns(Observable.Return(100));
vm.SomeClickEvent();
vm.Thing.Should().Be(100);
}
此测试失败。我相信这会失败,因为 MyViewModel
的构造函数在 IObservable
的不同实例上设置可观察管道比我在单元测试方法中设置的那个要好。
这里理想的解决方案是使用 IObservable<>
使用 AutoFixture 设置的实例,但我不确定如何最好地做到这一点。它以某种方式需要已经为我设置了一个预先构建的管道。
我发现的解决方法是不使用 AutoMock
AutoFixture
的功能并构造一个 Fixture
直接直接使用.Freeze()
和.Create()
方法按正确的顺序排列。然而,这可能会导致单元测试主体更难以阅读且不太干净。
如何继续实现此处所示的测试,同时能够在 SUT 的构造函数中使用任何可观察量之前对其进行设置?
最佳答案
我认为这里的问题是你从未真正运用可观察的,所以 Thing
保留 AutoFixture 在创建时分配给它的值。
在下面的示例中 Subject
被卡住为 IObservable<int>
然后将其解析为 StreamOfThings
的返回值。然后主题被迫触发订阅者。
[Test, AutoMockData]
public void Verify_some_behavior(
[Frozen(Matching.ImplementedInterfaces)] Subject<int> observable,
MyViewModel vm)
{
observable.OnNext(100);
vm.SomeClickEvent();
vm.Thing.Should().Be(100);
}
该示例等效于以下内容:
[Test, AutoMockData]
public void Verify_some_behavior(
Subject<int> observable,
[Frozen] Mock<IMyService> mockService,
MyViewModel vm)
{
mockService.Setup(x => x.StreamOfThings).Returns(observable);
observable.OnNext(100);
vm.SomeClickEvent();
vm.Thing.Should().Be(100);
}
这种编写测试的方式还应该使如何处理多个可观察属性变得显而易见。
关于c# - 使用 AutoFixture 中的 AutoMock 对构造函数中的响应式(Reactive)代码进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68848578/