【问题标题】:C# XUnit Strategy Pattern [closed]C# XUnit 策略模式
【发布时间】:2020-05-24 20:32:48
【问题描述】:

我很难为策略模式编写单元测试。 我正在写一个测试,它将调用 _mathStrategy.Calculate(a, b, Operator.Add) 并返回一个值。 问题是我不知道如何用正确的值实例化数学策略。 有人能告诉我正确的方法吗? 谢谢

public class HomeController : ControllerBase
{
    private readonly IMathStrategy _mathStrategy;

    public HomeController(IMathStrategy mathStrategy)
    {
        _mathStrategy = mathStrategy;
    }

    public IActionResult Index()
    {
        int a = 10;
        int b = 5;
        int result = _mathStrategy.Calculate(a, b, Operator.Add);
        return Content(result.ToString());
    }
}

public interface IMathOperator
{
    Operator Operator { get; }

    int Calculate(int a, int b);
}

public interface IMathStrategy
{
    int Calculate(int a, int b, Operator op);
}

public class MathStrategy : IMathStrategy
{
    private readonly IEnumerable<IMathOperator> _operators;

    public MathStrategy(IEnumerable<IMathOperator> operators)
    {
        _operators = operators;
    }

    public int Calculate(int a, int b, Operator op)
    {
        return _operators.FirstOrDefault(x => x.Operator == op)?.Calculate(a, b) ?? throw new ArgumentNullException(nameof(op));
    }
}

public enum Operator
{
    Add,
    Substract,
    Multiple,
    Divide
}

我的测试尝试

public class HomeControllerTest
{
    public IMathStrategy MathStrategy;
    public HomeControllerTest()
    {
        MathStrategy = new mathStrategy(new List<IMathOperator>());
    }
    [Fact]
    public void Test1()
    {
       var s = MathStrategy.Calculate(1, 2, Operator.Add);
    }
}

【问题讨论】:

  • 为什么阻止您通过 IEnumerable?另外,你的目标是什么?你想模拟策略吗?您想测试策略本身吗?
  • 我正在尝试编写一个返回从 MathStrategy 调用的值的单元测试。我不想模拟它。我真的想叫它
  • 谁阻止你写MathStrategy = new MathStrategy(new List&lt;IMathOperator&gt;(){ op1,op2,.. });这样的东西?使用IMathOperator的实际实现@
  • 我在正确实现 IMathOperator 时遇到问题
  • IMathOperator 的正确实现与 xunit 测试模式无关。您的问题和实际问题不匹配

标签: c# unit-testing xunit


【解决方案1】:

如果您的目标是确保您的MathStrategy 实现调用IMathOperator,而不是实际测试您的IMathOperator,那么您需要模拟您的IMathOperator,如下所示:

// arrange
var mock = new Moq<IMathOperator>();
mock.Setup(foo => foo.Operator).Returns(Operator.Add);

var strategy = new MathStrategy(new[] { mock .Value });

// act
strategy.Add(0, 0, Operator.Add);

// assert the strategy called the mock add operator
mock.Verify(foo => foo.Calculate(0, 0));

【讨论】:

  • 我的目标是测试 IMathOperator。我不想使用起订量。我想调用 actionMethod 并通过代码流并在其末尾返回正确的值。
  • 我也没有真正看到模拟这一点然后调用 mock.verify 的意义。我是单元测试新手。
  • 有两种方法可以测试strategy.Calculate() 方法。您可以验证结果,即它返回正确的值,或者您可以验证行为,即它调用正确的运算符。通常,当您测试一个协调其他对象的对象时,您想测试其行为。
【解决方案2】:

你可以在这里做很多事情。

如果您想测试调用IMathStrategy 的控制器的代码并返回正确的响应,您可以简单地模拟 IMathStrategy。创建您自己的类:MockMathStrategy : IMathStrategy,它将返回您定义的任何内容,或者您​​可以使用 Moq 库。

不过,我看不出有什么理由不能在那里使用IEnumerable&lt;IMathOperator&gt;。你仍然可以使用具体的实现。

更进一步,您可以测试 MathStrategy 本身,它调用正确的运算符,然后分别调用每个运算符。

编辑:为了澄清有关 IMathOperator 的问题,示例实现可能是:

public class AddOperator : IMathOperator
{
    public Operator Operator => Operator.Add;

    public int Calculate(int a, int b) 
    {
       return a + b;
    }
}

您现在可以在MathStrategy 构造函数中使用这些小类并测试具体实现。

要测试每个运算符的实现,您现在可以很容易地做到这一点,因为它们不需要任何其他依赖项

【讨论】:

  • 问题我不知道如何正确调用新的 MathStrategy。 MathStrategy = new MathStrategy(new List() { Operator.Add });我在这里传入什么 {"""""""}。使用了 Operator Operator { get; } int Calculate(int a, int b);。
  • 我已经用 AddOperator 的示例实现编辑了我的答案
  • 对不起,你是说我应该将每个操作注入到 MathStrategy 构造函数中,因为我试图避免这样做。对不起,我是这个单元测试的新手
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-15
  • 1970-01-01
相关资源
最近更新 更多