如何使用 AutoFixture AutoMoq 将测试参数中定义的模拟类型自动注入 SUT

How to auto inject mocked types defined in test parameters into SUT using AutoFixture AutoMoq

假设我有以下代码示例:

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 的情况一样)时,这就成了一个问题。 =18=]

理想情况下,我希望能够按以下方式定义测试:

[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", actual);
   mockBar.Verify(x => x.GetMessage(), 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());
}