【问题标题】:AutoFixture Build-Freeze-Create sequenceAutoFixture 构建-冻结-创建序列
【发布时间】:2017-06-12 15:39:05
【问题描述】:

我刚刚注意到,每当我在Build<>()-Create() 之间的夹具上执行Freeze 调用时,Freezes 都不会被应用。是 AutoFixture 的预期行为还是错误?

说清楚:

var fixture = new Fixture().Customize(new AutoMoqCustomization())
var builder = fixture.Build<SomeType>();
fixture.Freeze<Mock<ISomeInterface>>().Setup(m => m.SomeProperty).Returns(10);
var sut = builder.Create();
// if SomeType uses ISomeInterface.SomeProperty it will get 0 returned - *incorrect*

这很好用:

var fixture = new Fixture().Customize(new AutoMoqCustomization())
fixture.Freeze<Mock<ISomeInterface>>().Setup(m => m.SomeProperty).Returns(10);
var sut = fixture.Create<SomeType>();
// if SomeType uses ISomeInterface.SomeProperty it will get 10 returned - correct

【问题讨论】:

    标签: c# unit-testing moq autofixture


    【解决方案1】:

    如果你在调用构建器之前冻结它会起作用

    冻结-构建-创建序列

    [TestClass]
    public class AutoFixtureTests {
        [TestMethod]
        public void _FreezeBuildCreate() {
            //Arrange
            var expected = 10;
            var fixture = new Fixture().Customize(new AutoMoqCustomization());
            fixture.Freeze<Mock<ISomeInterface>>().Setup(m => m.SomeProperty).Returns(expected);
            var builder = fixture.Build<SomeType>();
            var sut = builder.Create();
    
            //Act
            var actual = sut.GetA();
    
            //Assert
            Assert.AreEqual(expected, actual);
        }
    
        public class SomeType {
            private ISomeInterface a;
            public SomeType(ISomeInterface a) {
                this.a = a;
            }
            public int GetA() {
                return a.SomeProperty;
            }
        }
    
        public interface ISomeInterface {
            int SomeProperty { get; set; }
        }
    }
    

    如果你看Build方法的定义

    自定义单个对象的创建算法,有效 关闭 Ploeh.AutoFixture.IFixture 上的所有自定义。

    如果在冻结之前调用 build 之后的所有自定义设置都不会生效。

    【讨论】:

    • 感谢您的解释。我实际上以另一种方式解决了这个问题 - 在 Build-Create 之间调用了自定义事件,这样我就可以将序列保持在不会干扰 Freezes 的地方
    【解决方案2】:

    所以这就是我自己解决这个问题的方法。由于在选择Build-Create 的放置位置时我没有太多选择,因此不得不为此使用事件。哦,我不想让Create 虚拟化。

    这是一些伪代码:

    public class BaseSutBuilder<TSut> {
        // other weird stuff...
    
        // somewhere in ctor:
        protected BaseSutBuilder() {
            SutBuilders = _ => {};
        }
    
        protected Action<ICustomizationComposer<TSut>> SutBuilders { get; }
    
        public TSut Create() {
            var builder = _fixture.Build<TSut>();
            SutBuilders(builder);
            return builder.Create();
        }
    }
    
    public class SomeTypeSutBuilder: BaseSutBuilder<SomeType> {
        public SomeTypeSutBuilder() {
            SutBuilders += c => c.With(.......
            SutBuilders += c => c.With(.......
        }
    }
    

    【讨论】: