Different return values the first and second time with Moq

marcus picture marcus · Sep 2, 2011 · Viewed 88k times · Source

I have a test like this:

    [TestCase("~/page/myaction")]
    public void Page_With_Custom_Action(string path) {
        // Arrange
        var pathData = new Mock<IPathData>();
        var pageModel = new Mock<IPageModel>();
        var repository = new Mock<IPageRepository>();
        var mapper = new Mock<IControllerMapper>();
        var container = new Mock<IContainer>();

        container.Setup(x => x.GetInstance<IPageRepository>()).Returns(repository.Object);

        repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageModel.Object);

        pathData.Setup(x => x.Action).Returns("myaction");
        pathData.Setup(x => x.Controller).Returns("page");

        var resolver = new DashboardPathResolver(pathData.Object, repository.Object, mapper.Object, container.Object);

        // Act
        var data = resolver.ResolvePath(path);

        // Assert
        Assert.NotNull(data);
        Assert.AreEqual("myaction", data.Action);
        Assert.AreEqual("page", data.Controller);
    }

GetPageByUrl runs twice in my DashboardPathResolver, how can I tell Moq to return null the first time and pageModel.Object the second?

Answer

stackunderflow picture stackunderflow · Nov 30, 2013

With the latest version of Moq(4.2.1312.1622), you can setup a sequence of events using SetupSequence. Here's an example:

_mockClient.SetupSequence(m => m.Connect(It.IsAny<String>(), It.IsAny<int>(), It.IsAny<int>()))
        .Throws(new SocketException())
        .Throws(new SocketException())
        .Returns(true)
        .Throws(new SocketException())
        .Returns(true);

Calling connect will only be successful on the third and fifth attempt otherwise an exception will be thrown.

So for your example it would just be something like:

repository.SetupSequence(x => x.GetPageByUrl<IPageModel>(virtualUrl))
.Returns(null)
.Returns(pageModel.Object);