gpt4 book ai didi

c# - Moq 一个具体的类方法调用

转载 作者:行者123 更新时间:2023-11-30 15:58:37 25 4
gpt4 key购买 nike

我有一个像这样的设置,其中包含一个在我要测试的方法中实例化的具体类。我想模拟这个具体类而不是让它执行里面的代码。因此,不应抛出异常:

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,但它并没有给我任何帮助。无论如何我可以轻松解决这个问题而无需依赖注入(inject)这些类和添加接口(interface)?这可能只使用最小起订量吗?

目前我唯一能想到的就是将 Execute 方法移动到 Executor 类中并将它们重命名为 ExecuteFoo()ExecuteBar(),但我有需要移动大量代码,因此它们必须是部分类(子类?)。

最佳答案

问题不在于方法的模拟,而在于具体类的创建。 FooBar的创建需要从Executor中倒过来。它负责执行 Action ,而不是创建 Action 。为此,创建了此接口(interface)来处理创建。

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

}

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

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

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;
}
}

完成重构后,可以使用假 Action 测试执行器。

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();

关于c# - Moq 一个具体的类方法调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42983208/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com