繁体   English   中英

Moq是一个具体的类方法调用

[英]Moq a concrete class method call

我有一个这样的设置,一个具体的类在我想测试的方法中实例化。 我想模仿这个具体的类,没有它执行里面的代码。 因此,不应抛出任何异常:

public class Executor
{
    public bool ExecuteAction(ActionRequest request)
    {
        switch (request.ActionType)
        {
            case ActionType.Foo:
                var a = new Foo();
                return a.Execute(request);
            case ActionType.Bar:
                var b = new Bar();
                return b.Execute(request);
        }

        return true;
    }
}

public class Foo
{
    public virtual bool Execute(ActionRequest request)
    {
        throw new NotImplementedException();
    }
}

public class Bar
{
    public virtual bool Execute(ActionRequest request)
    {
        throw new NotImplementedException();
    }
}

我的NUnit测试看起来像这样:

[Test]
public void GivenARequestToFooShouldExecuteFoo()
{
    var action = new Mock<Foo>();
    action.Setup(x => x.Execute(It.IsAny<ActionRequest>())).Returns(true);

    var sut = new Mock<Executor>();
    sut.Object.ExecuteAction(new ActionRequest
    {
        ActionType = ActionType.Foo
    });
}

[Test]
public void GivenARequestToBarShouldExecuteBar()
{
    var action = new Mock<Bar>();
    action.Setup(x => x.Execute(It.IsAny<ActionRequest>())).Returns(true);

    var sut = new Mock<Executor>();
    sut.Object.ExecuteAction(new ActionRequest
    {
        ActionType = ActionType.Bar
    });
}

我摆弄着CallBase ,但它并没有把我CallBase任何地方。 无论如何,我可以轻松地解决这个问题,而无需依赖注入这些类并添加接口? 这可能只是使用Moq吗?

我目前唯一能想到的就是将Execute方法移动到Executor类中并将它们重命名为ExecuteFoo()ExecuteBar() ,但是我有很多代码要移动所以它们必须是部分类(sub)班?)。

问题不在于模拟方法,而在于创建具体类。 FooBar的创建需要从Executor反转出来。 它负责执行操作,而不是创建操作。 这个界面是为了处理创建而创建的。

public interface IActionCollection : IDictionary<ActionType, Func<IExecute>> {

}

将其视为工厂集合或创作策略集合。

为操作创建了一个通用接口。

public interface IExecute {
    bool Execute(ActionRequest request);
}

public class Foo : IExecute {
    public virtual bool Execute(ActionRequest request) {
        throw new NotImplementedException();
    }
}

public class Bar : IExecute {
    public virtual bool Execute(ActionRequest request) {
        throw new NotImplementedException();
    }
}

并且Executor被重构为使用依赖性反转。

public class Executor {
    readonly IActionCollection factories;

    public Executor(IActionCollection factories) {
        this.factories = factories;
    }

    public bool ExecuteAction(ActionRequest request) {
        if (factories.ContainsKey(request.ActionType)) {
            var action = factories[request.ActionType]();
            return action.Execute(request);
        }
        return false;
    }
}

完成该重构后,Executor可以使用虚假动作进行测试。

public void GivenARequestToFooShouldExecuteFoo() {
    //Arrange
    var expected = true;
    var key = ActionType.Foo;

    var action = new Mock<Foo>();
    action.Setup(x => x.Execute(It.IsAny<ActionRequest>())).Returns(expected);

    var actions = new Mock<IActionCollection>();
    actions.Setup(_ => _[key]).Returns(() => { return () => action.Object; });
    actions.Setup(_ => _.ContainsKey(key)).Returns(true);

    var sut = new Executor(actions.Object);
    var request = new ActionRequest {
        ActionType = ActionType.Foo
    };

    //Act
    var actual = sut.ExecuteAction(request);

    //Assert
    Assert.AreEqual(expected, actual);
}

工厂集合的生产实现可能如下所示

public class ActionCollection : Dictionary<ActionType, Func<IExecute>>, IActionCollection {
    public ActionCollection()
        : base() {
    }
}

并根据您的具体类型进行相应配置。

var factories = ActionCollection();
factories[ActionType.Foo] = () => new Foo();
factories[ActionType.Bar] = () => new Bar();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM