Valores de retorno diferentes la primera y segunda vez con Moq

Resuelto marcus asked hace 13 años • 9 respuestas

Tengo una prueba como esta:

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

GetPageByUrlse ejecuta dos veces en mi DashboardPathResolver, ¿cómo puedo decirle a Moq que regrese nullla primera vez y pageModel.Objectla segunda?

marcus avatar Sep 03 '11 01:09 marcus
Aceptado

Con la última versión de Moq (4.2.1312.1622), puede configurar una secuencia de eventos usando SetupSequence . He aquí un ejemplo:

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

Llamar a connect solo será exitoso en el tercer y quinto intento; de lo contrario, se generará una excepción.

Entonces, para tu ejemplo, sería algo como:

repository.SetupSequence(x => x.GetPageByUrl<IPageModel>(virtualUrl))
.Returns(null)
.Returns(pageModel.Object);
stackunderflow avatar Nov 29 '2013 23:11 stackunderflow

Las respuestas existentes son geniales, pero pensé en incluir mi alternativa que solo usa System.Collections.Generic.Queuey no requiere ningún conocimiento especial del marco simulado, ¡ya que no tenía ninguno cuando lo escribí! :)

var pageModel = new Mock<IPageModel>();
IPageModel pageModelNull = null;
var pageModels = new Queue<IPageModel>();
pageModels.Enqueue(pageModelNull);
pageModels.Enqueue(pageModel.Object);

Entonces...

repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(pageModels.Dequeue);
mo. avatar Mar 05 '2013 23:03 mo.

Ahora puedes usar SetupSequence. Ver esta publicación .

var mock = new Mock<IFoo>();
mock.SetupSequence(f => f.GetCount())
    .Returns(3)  // will be returned on 1st invocation
    .Returns(2)  // will be returned on 2nd invocation
    .Returns(1)  // will be returned on 3rd invocation
    .Returns(0)  // will be returned on 4th invocation
    .Throws(new InvalidOperationException());  // will be thrown on 5th invocation
ilmatte avatar Feb 22 '2013 12:02 ilmatte

Puede utilizar una devolución de llamada al configurar su objeto simulado. Eche un vistazo al ejemplo de Moq Wiki ( https://github.com/Moq/moq4/wiki/Quickstart ).

// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
    .Returns(() => calls)
    .Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThing());

Su configuración podría verse así:

var pageObject = pageModel.Object;
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageObject).Callback(() =>
            {
                // assign new value for second call
                pageObject = new PageModel();
            });
Dan avatar Sep 02 '2011 18:09 Dan

Agregar una devolución de llamada no funcionó para mí, usé este enfoque en su lugar http://haacked.com/archive/2009/09/29/moq-sequences.aspx y terminé con una prueba como esta:

    [TestCase("~/page/myaction")]
    [TestCase("~/page/myaction/")]
    public void Page_With_Custom_Action(string virtualUrl) {

        // 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>(virtualUrl)).ReturnsInOrder(null, 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(virtualUrl);

        // Assert
        Assert.NotNull(data);
        Assert.AreEqual("myaction", data.Action);
        Assert.AreEqual("page", data.Controller);
    }
marcus avatar Sep 04 '2011 16:09 marcus