【问题标题】:Moq tests using ExpectSet() with It.Is<T>() aren't behaving as... expected将 ExpectSet() 与 It.Is<T>() 一起使用的 Moq 测试的行为不符合...预期
【发布时间】:2008-12-11 00:58:17
【问题描述】:

我已将行为隔离到以下测试用例中。我会感谢任何能告诉我如何期待/验证为 List&lt;T&gt; 属性设置的属性的人 - 似乎 It.Is&lt;T&gt;(predicate) 内部发生了一些事情,这对我来说现在没有多大意义.示例代码将作为 VS2008 的控制台应用程序运行 - 您需要添加对 Moq 2.6 的引用(我在 2.6.1014.1) - 请尝试取消注释不同的 ExpectSet 语句以查看发生了什么...

using System;
using Moq;
using System.Collections.Generic;

namespace MoqDemo {

    public interface IView {
        List<string> Names { get; set; }
    }

    public class Controller {
        private IView view;

        public Controller(IView view) {
            this.view = view;
        }

        public void PopulateView() {
            List<string> names = new List<string>() { "Hugh", "Pugh", "Barney McGrew" };
            view.Names = names;
        }

        public class MyApp {
            public static void Main() {
                Mock<IView> mockView = new Mock<IView>();

                // This works - and the expectation is verifiable.
                mockView.ExpectSet(mv => mv.Names);

                // None of the following can be verified.
                // mockView.ExpectSet(mv => mv.Names, It.Is<Object>(o => o != null));
                // mockView.ExpectSet(mv => mv.Names, It.Is<List<string>>(names => names.Count == 3));
                // mockView.ExpectSet(mv => mv.Names, It.IsAny<IList<String>>());

                Controller controller = new Controller(mockView.Object);
                controller.PopulateView();
                try {
                    mockView.VerifyAll();
                    Console.WriteLine("Verified OK!");
                } catch (MockException ex) {
                    Console.WriteLine("Verification failed!");
                    Console.WriteLine(ex.Message);
                }
                Console.ReadKey(false);
            }
        }
    }
}

【问题讨论】:

    标签: unit-testing tdd mocking moq


    【解决方案1】:

    我没有使用最新版本的 Moq,所以我没有使用两个参数的 ExpectSet 重载,但我在这种模式上取得了一些成功:

    mockView.ExpectSet(mv => mv.Names).Callback(n => Assert.That(n != null));
    

    如果分配给 .Names 的值与谓词不匹配,回调中的 Assert(来自 NUnit)调用将引发异常。但是,当测试失败时,它确实很难追踪。我同意传递 It.Is 或 It.IsAny 作为第二个参数的能力会很方便。

    【讨论】:

    • 没有这样的重载 - 即使在最新版本中 - 但回调语法正是我正在寻找的。谢谢。
    【解决方案2】:

    ExpectSet() 的第二个参数是您期望的值。在这种情况下,您不能使用 It.Is&lt;T&gt;,因为没有采用谓词的重载 - 尽管它会很好;)这是您示例的(简化)摘录,说明了值的使用:

    var mockView = new Mock<IView>();
    var list = new List<string> { "Hugh", "Pugh", "Barney McGrew" };
    
    mockView.ExpectSet(mv => mv.Names, list);
    
    mockView.Object.Names = list;
    

    希望对您有所帮助。

    编辑:修正错字。

    【讨论】:

      【解决方案3】:

      顺便说一句,ExpectSet 不支持 It.Is。您的代码编译只是因为它们在用作值(而不是表达式)时是常规方法调用,而在 Expect expression 中使用时,它们由 Moq 预处理并赋予特定含义(而不是所有 It.Is 成员实际返回的 null/默认值)。

      您可以在给定属性 (mockView.Stub(mv => mv.Names)) 上使用存根行为,然后在执行后直接断言其值。

      【讨论】:

        【解决方案4】:

        Moq 不提供接收 It.IsAny 的重载,因为它实际上与在不传递预期值的情况下调用 ExpectSet 相同;)

        【讨论】:

          猜你喜欢
          • 2013-02-28
          • 2021-10-16
          • 2018-04-13
          • 1970-01-01
          • 2018-03-19
          • 1970-01-01
          • 2023-03-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多