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);
}
}
}
}
source to share
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.
source to share
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.
source to share
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.
source to share