问题描述
public interface IBar
{
string GetMessage();
}
public class Foo
{
private readonly IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
public string Prefix { get; set; }
public string RetrieveMessage()
{
if (string.IsNullOrWhiteSpace(Prefix)) return string.Empty;
return $"{Prefix} {this.bar.GetMessage()}";
}
}
我目前有一个如下所示的测试:
[Test,automoqData]
public void TestThatIHavetoManuallyCreateSUT(Mock<IBar> mockBar)
{
// Arrange
mockBar.Setup(x => x.GetMessage()).Returns("World");
Foo sut = new Foo(mockBar.Object)
{
Prefix = "Hello",};
// Act
var actual = sut.RetrieveMessage();
// Assert
Assert.AreEqual($"{sut.Prefix} World",actual);
mockBar.Verify(x => x.GetMessage(),Times.Once());
}
这工作正常,但存在需要在测试中手动创建 SUT 的问题。当我的代码依赖于需要在其中包含一些数据的属性,并且需要始终记住使用某个值初始化属性时,这就会成为一个问题(如 Foo.Prefix
的情况)。
理想情况下,我希望能够通过以下方式定义测试:
[Test,automoqData]
public void TestWhereAutoDataCreatesTheSUT(Mock<IBar> mockBar,Foo sut)
{
// Arrange
mockBar.Setup(x => x.GetMessage()).Returns("World");
// Act
var actual = sut.RetrieveMessage();
// Assert
Assert.AreEqual($"{sut.Prefix} World",Times.Once());
}
其中 SUT 是使用 mockBar
实例自动创建的,然后我可以在测试中进一步使用它。
上面的代码不起作用,因为它会自动模拟一个新实例 IBar
,并且不允许我访问底层模拟对象。
我的 automoqDataAttribute
没有任何花哨的东西:
public class automoqDataAttribute : AutoDataAttribute
{
public automoqDataAttribute() : base(() => new Fixture().Customize(new automoqCustomization() { ConfigureMembers = true }))
{
}
}
但我想如果为了实现这一点需要进行任何设置,它会在这里。
有没有办法使用 AutoFixture automoq 将测试参数中定义的模拟类型自动注入 SUT?
解决方法
基于 following article,我建议重构您的测试
[Test,AutoMoqData]
public void TestWhereAutoDataCreatesTheSUT([Frozen]IBar bar,Foo sut) {
// Arrange
Mock<IBar> mockBar = Mock.Get(bar);
mockBar.Setup(x => x.GetMessage()).Returns("World");
// Act
var actual = sut.RetrieveMessage();
// Assert
Assert.AreEqual($"{sut.Prefix} World",actual);
mockBar.Verify(x => x.GetMessage(),Times.Once());
}