使用带有It.Is <t>()的ExpectSet()的Moq测试表现不如...预期</t>

时间:2008-12-11 00:58:17

标签: unit-testing tdd mocking moq

我已将行为隔离到以下测试用例中。我会感激任何能告诉我如何期望/验证List<T>属性的属性集的人 - 看来It.Is<T>(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);
            }
        }
    }
}

4 个答案:

答案 0 :(得分:1)

ExpectSet()的第二个参数是您期望的值。在这种情况下你不能使用It.Is<T>,因为没有带谓词的重载 - 虽然它会很好;)这是你的样本的一个(简化的)摘录,说明了值的使用:

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

mockView.ExpectSet(mv => mv.Names, list);

mockView.Object.Names = list;

希望有所帮助。

编辑:修正错字。

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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