Moq using ExpectSet () with It.Is <T> () doesn't behave as ... expected

I have isolated the behavior in the following test case. I would be grateful to anyone who can tell me how to expect / check a property set for a property List<T>

- it looks like something is going on internally It.Is<T>(predicate)

that doesn't make much sense to me right now, The sample code will run as a console app from VS2008 - you will need to add a link to Moq 2.6 (I'm on 2.6.1014.1) - try to expose various ExpectSet expressions to see what's going on ...

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

      

0


source to share


4 answers


I'm not using the most recent version of Moq, so I don't have an ExpectSet overload that takes two parameters, but I've had some success with this pattern:

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

      



Calling Assert (from NUnit) in the callback throws an exception if the value assigned to .Names does not match the predicate. However, it is difficult to track down when a test fails. I agree that being able to pass It.Is or It.IsAny as the second parameter is handy.

+1


source


The second parameter to ExpectSet () is the value you expect. You cannot use It.Is<T>

in this case as there is no overload that takes a predicate - although it would be nice;) Here's a (simplified) excerpt from your example illustrating the use of a value:

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

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

mockView.Object.Names = list;

      



Hope it helps.

Edit: Fixed a typo.

+1


source


BTW, It.Is is not supported in ExpectSet. Your code only compiles because they are regular method calls when used as values ​​(as opposed to expressions), whereas when used in an Expect expression, they are preprocessed by Moq and given a specific value (and not null / default, which is all .Is members are actually being returned).

You can use the stub behavior on a given property (mockView.Stub (mv => mv.Names)) and then immediately assert its value after execution.

+1


source


Moq does not provide an overload that takes It.IsAny, as it is effectively the same as calling ExpectSet without passing the expected value;)

0


source







All Articles