【问题标题】:Mocking Func<Tin,Tout>模拟函数<Tin,Tout>
【发布时间】:2019-08-07 16:54:37
【问题描述】:

我有一些将 Funcs 传递给某些方法的用例。我想要做的是使用 Moq 创建一个扩展或帮助程序,使我的测试能够轻松创建函数。这个助手的目标是

  1. 易于定义具有预期输入和固定输出的函数
  2. 如果未调用函数,测试应该失败
  3. 如果函数被错误的输入调用,测试应该会失败
  4. 使用It.IsAny&lt;TInput&gt;() 应该像在任何模拟中一样工作

我得到了我想要的大部分东西,但第 4 项却让我望而却步。这是我不明白的难以捉摸的失败测试的扩展和测试

public static Func<TIn, TOut> FixedFunc<TIn, TOut>(this MockRepository repo, TIn expectedInput, TOut fixedOutput)
{
    var verifier = repo.Create<IInvokable<TIn, TOut>>(MockBehavior.Strict);

    verifier.Setup(m => m.Invoke(expectedInput))
        .Returns(fixedOutput);

    return input => verifier.Object.Invoke(input);
}

public static Func<TIn, TOut> FixedFunc<TIn, TOut>(this MockRepository repo, TOut fixedOutput)
{
    var verifier = repo.Create<IInvokable<TIn, TOut>>(MockBehavior.Strict);

    verifier.Setup(m => m.Invoke(It.IsAny<TIn>()))
        .Returns(fixedOutput);

    return input => verifier.Object.Invoke(input);
}

public interface IInvokable<TIn, TOut>
{
    TOut Invoke(TIn input);
}

这里是测试

[Fact] // succeeds
public void MockFunc_SameObject_RetursResult()
{
    var expectedInput= new object();
    var expectedOutput = 2;

    var repo = new MockRepository(MockBehavior.Strict);
    var function = repo.FixedFunc(exptecedInput, expectedOutput);

    var output = function(expectedInput);
    Assert.Equal(expectedOutput, output);

    repo.VerifyAll();
}

[Fact]
// Fails with the following exception:
// "Moq.MockException: IInvokable`2.Invoke(object) invocation failed with mock behavior Strict.
// All invocations on the mock must have a corresponding setup."
public void MockFunc_IsAny_RetursResult()
{
    var exptecedInput = new object();
    var expectedOutput = 2;

    var repo = new MockRepository(MockBehavior.Strict);
    var function = repo.FixedFunc(It.IsAny<object>(), expectedOutput);

    var output = function(exptecedInput);
    Assert.Equal(expectedOutput, output);

    repo.VerifyAll();
}

[Fact] // succeeds
public void MockFunc_WithAny_RetursResult()
{
    var expectedOutput = 2;

    var repo = new MockRepository(MockBehavior.Strict);
    var function = repo.FixedFunc<object, int>(expectedOutput);

    var output = function(new object());
    Assert.Equal(expectedOutput, output);

    repo.VerifyAll();
}

我不明白如何使用 It.IsAny 对 FixedFunc&lt;TOut> 有效,但对 FixedFunc&lt;TIn, TOut 无效>

【问题讨论】:

    标签: c# testing moq


    【解决方案1】:

    注意一件事,如果您评估It.Any&lt;object&gt;(),结果将是null。在Func&lt;TIn, TOut&gt; 的情况下,您正在有效地为以下各项创建设置:

    verifier.Setup(m => m.Invoke(null)).Returns(fixedOutput);
    

    然后使用var exptecedInput = new object(); 调用它。在VerifyAll 期间,当moq 尝试评估和匹配参数时,它不能这样做,因为null != new object()


    您要么想用It.Any&lt;object&gt;() 调用方法,要么重新设计一个扩展以传递Expression 并用Expression 而不是特定对象注册设置。

    [Fact] // This will pass
    public void MockFunc_IsAny_RetursResult()
    {
        var expectedOutput = 2;
    
        var repo = new MockRepository(MockBehavior.Strict);
        var function = repo.FixedFunc(It.IsAny<object>(), expectedOutput);
    
        var output = function(It.IsAny<object>());
    
        Assert.Equal(expectedOutput, output);
        repo.VerifyAll();
    }
    

    【讨论】:

    • 好吧,在调用中使用 It.IsAny 会破坏事物的目的。我看到了 It.IsAny() 将如何返回默认值(T),但是为什么当我在与设置调用相同的上下文中使用 It.IsAny 而不是当我将 It.IsAny 作为参数传递时它会起作用?我什至尝试传递 It.IsAny (作为 Func)并在设置期间调用它,但这也失败了。传递一个表达式让我失去了所有简单的设置......还有其他想法吗?
    • @MarcelBatista 我同意传递It.IsAny 没有意义,只是为了解释。它之所以有效,是因为如果您在设置中提供它It.IsAny 将被捕获为表达式,稍后可以由moq 评估。如果您将它作为参数传递,那么您将丢失表达式,但仅发送 default(object)moq 的值,然后不知道原始表达式是什么。您需要以某种方式发送该表达式,我认为您尝试用一个值有效地创建设置然后用另一个值验证它是不可能的...
    猜你喜欢
    • 2019-09-04
    • 2019-11-26
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多