devlooped / moq

The most popular and friendly mocking framework for .NET
Other
5.92k stars 802 forks source link

nUnit / moq behaviour always returns false #758

Closed rickersilva closed 5 years ago

rickersilva commented 5 years ago

I'm new to unit testing with nUnit and Moq and have run into an issue seting behaviours for a method in a dbprovider. I'm tryin to test a validation method that invokes an Exists method in ICoDbProvider. When false, the method throws an excpetion, and it is working nice. When true, the method should go ahead until the return true; statement at the end of the method. This is the method tested:

private bool ValidateReciboCajaModel(ReciboCajaModel model)
{
        if (model == null)
            throw new ArgumentException("El modelo ha llegado nulo");

        if (string.IsNullOrWhiteSpace(model.AccionARealizar))
            throw new ArgumentException("No se ha definido una Acción a realizar");

        if (!_accionARealizarService.Exists(new AccionARealizarEntity(model)))
            throw new ArgumentException(@"No es una ""acción a realizar"" válida");

        if (string.IsNullOrWhiteSpace(model.CentroCostos))
            throw new ArgumentException("No se ha definido ningún centro de costos");

        if (!_centroCostosService.Exists(new CentroCostosEntity(model)))
            throw new Exception("No es un centro de costos válido");

        if (String.IsNullOrWhiteSpace(model.CuentaIngresoDinero))
            throw new Exception("No es una cuenta de Ingreso válida");

        if (!_terceroService.Exists(new TerceroEntity(model)))
            throw new Exception("No es un tercero registrado");

        if (String.IsNullOrWhiteSpace(model.Tercero))
            throw new Exception("No es un tercero válido");

        if (!_tipoReciboCajaService.Exists(new TipoReciboCajaEntity(model)))
            throw new Exception("No es un recibo de caja registrado");

        if (String.IsNullOrWhiteSpace(model.TipoReciboCaja))
            throw new Exception("No es un recibo de caja válido");

        if (!(0 < model.ValorPagado && model.ValorPagado <= 999999999999d))
            throw new Exception("El valor pagado no es válido");

        return true;

}

The test was originally generated by Intellitest, and it generated a scaffolding for private method testing. The test method looks like this.

    [Test]
    [PexGeneratedBy(typeof(ReciboCajaBizTest))]
    [PexRaisedException(typeof(TargetInvocationException))]
    public void ValidateReciboCajaModel_ValidModel()
    {
        bool b;
        TargetInvocationException receivedException = new TargetInvocationException(null);

        ReciboCajaModel s1 = new ReciboCajaModel();
        var accionARealizarService = new Mock<ICoDbProvider>();
        var centroCostosService = new Mock<ICoDbProvider>();
        var terceroService = new Mock<ICoDbProvider>();
        var tipoReciboCajaService = new Mock<ICoDbProvider>();

        s1.TipoReciboCaja = "RC0";
        s1.Numero = 0;
        s1.Tercero = "tercero existente";
        s1.AccionARealizar = "some action";
        s1.FechaElaboracion = default(DateTime);
        s1.CentroCostos = "cc1";
        s1.CuentaIngresoDinero = "Débito";
        s1.ValorPagado = 1000000d;

        accionARealizarService.Setup(m => m.Exists(new AccionARealizarEntity(s1))).Returns(true);
        centroCostosService.Setup(m => m.Exists(new CentroCostosEntity(s1))).Returns(true);
        terceroService.Setup(m => m.Exists(new TerceroEntity(s1))).Returns(true);
        tipoReciboCajaService.Setup(m => m.Exists(new TipoReciboCajaEntity(s1))).Returns(true);

        ReciboCajaBiz s0 = new ReciboCajaBiz(null, accionARealizarService.Object, centroCostosService.Object,terceroService.Object,tipoReciboCajaService.Object);

        b = this.ValidateReciboCajaModel(s0, s1);

        Assert.AreEqual(true, b);
    }

This is the case everything in the Model is right and the method should return a valid flag. I have this weird behaviour while debugging. Right after seting Mocks behaviour I called in Watch window the method, and it return false, as shown in the picture

image

I also have a method that tests the accionARealizar object does not exists, and it returns false as set. But I doubt it is working correctly.

This was originally posted in stackoverflow https://stackoverflow.com/questions/54875460/nunit-moq-behaviour-always-returns-false

stakx commented 5 years ago

You already got an answer on Stack Overflow, which explains this. Calling new AccionARealizarEntity(s1) twice will give you two distinct objects (even though they might be equal in all their properties), so in the Watch window you're making a call that has no corresponding setup.

Either implement value equality semantics on your AccionARealizarEntity type by overriding Equals, GetHashCode etc. or turn it from a class to a struct, if that is appropriate for your object model.

Or cache the value of one call to new AccionARealizarEntity(s1) somewhere, then use that cached instance in both your setup and the Watch expression.

P.S.: Please don't cross-post.

rickersilva commented 5 years ago

sorry for the cross posting. I did think twice about it, but decided to post anyway. Thank you for your explanation. problem is solved.

Hope redundancy may help others as well.

stakx commented 5 years ago

Good to hear you got your tests working!