加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 使用例如创建模拟和匿名对象的混合. Moq和AutoFixture?

发布时间:2020-12-15 08:38:17 所属栏目:百科 来源:网络整理
导读:我在工作期间遇到的课程如下: public class MyObject{ public int? A {get; set;} public int? B {get; set;} public int? C {get; set;} public virtual int? GetSomeValue() { //simplified behavior: return A ?? B ?? C; } } 问题是我有一些代码可以访
我在工作期间遇到的课程如下:
public class MyObject
{
  public int? A {get; set;}
  public int? B {get; set;}
  public int? C {get; set;}
  public virtual int? GetSomeValue()
  {
    //simplified behavior:
    return A ?? B ?? C;
  }  
}

问题是我有一些代码可以访问A,B和C并调用GetSomeValue()方法(现在,我认为这不是一个好的设计,但有时我的双手并列;-)).我想创建一个这个对象的模拟,同时将A,B和C设置为某些值.所以,当我使用moq时:

var m = new Mock<MyObject>() { DefaultValue = DefaultValue.Mock };

让我在GetSomeValue()方法上设置一个结果,但所有属性都设置为null(使用Setup()设置所有属性非常麻烦,因为真实对象是一个讨厌的数据对象,并且具有比上面更多的属性简化的例子).

所以另一方面,使用像这样的AutoFixture:

var fixture = new Fixture();
var anyMyObject = fixture.CreateAnonymous<MyObject>();

让我无法对GetSomeValue()方法进行调用.

有没有办法将两者结合起来,拥有匿名值和设置呼叫结果的能力?

编辑

根据nemesv的答案,我推导出以下实用方法(希望我做对了):

public static Mock<T> AnonymousMock<T>() where T : class
{
  var mock = new Mock<T>();
  fixture.Customize<T>(c => c.FromFactory(() => mock.Object));
  fixture.CreateAnonymous<T>();
  fixture.Customizations.RemoveAt(0);
  return mock;
}

解决方法

这实际上可以使用AutoFixture,但它确实需要一些调整.可扩展性点都在那里,但我承认在这种情况下,解决方案不是特别容易被发现的.

如果您希望它与嵌套/复杂类型一起使用会变得更加困难.

给定上面的MyObject类,以及此MyParent类:

public class MyParent
{
    public MyObject Object { get; set; }

    public string Text { get; set; }
}

这些单元测试全部通过:

public class Scenario
{
    [Fact]
    public void CreateMyObject()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyObject>();

        Assert.NotNull(actual.A);
        Assert.NotNull(actual.B);
        Assert.NotNull(actual.C);
    }

    [Fact]
    public void MyObjectIsMock()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyObject>();

        Assert.NotNull(Mock.Get(actual));
    }

    [Fact]
    public void CreateMyParent()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyParent>();

        Assert.NotNull(actual.Object);
        Assert.NotNull(actual.Text);
        Assert.NotNull(Mock.Get(actual.Object));
    }

    [Fact]
    public void MyParentIsMock()
    {
        var fixture = new Fixture().Customize(new MockHybridCustomization());

        var actual = fixture.CreateAnonymous<MyParent>();

        Assert.NotNull(Mock.Get(actual));
    }
}

什么是MockHybridCustomization?这个:

public class MockHybridCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(
            new MockPostprocessor(
                new MethodInvoker(
                    new MockConstructorQuery())));
        fixture.Customizations.Add(
            new Postprocessor(
                new MockRelay(t =>
                    t == typeof(MyObject) || t == typeof(MyParent)),new AutoExceptMoqPropertiesCommand().Execute,new AnyTypeSpecification()));
    }
}

MockPostprocessor,MockConstructorQuery和MockRelay类在AutoMoq extension到AutoFixture中定义,因此您需要添加对此库的引用.但请注意,不需要添加AutoMoqCustomization.

AutoExceptMoqPropertiesCommand类也是为这种场合定制的:

public class AutoExceptMoqPropertiesCommand : AutoPropertiesCommand<object>
{
    public AutoExceptMoqPropertiesCommand()
        : base(new NoInterceptorsSpecification())
    {
    }

    protected override Type GetSpecimenType(object specimen)
    {
        return specimen.GetType();
    }

    private class NoInterceptorsSpecification : IRequestSpecification
    {
        public bool IsSatisfiedBy(object request)
        {
            var fi = request as FieldInfo;
            if (fi != null)
            {
                if (fi.Name == "__interceptors")
                    return false;
            }

            return true;
        }
    }
}

该解决方案提供了该问题的一般解决方案.但是,它还没有经过广泛测试,所以我很乐意得到反馈.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读