Reputation: 1135
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
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.
Update
As requested in comments below, this is ReciboCajaModel
public class ReciboCajaModel
{
[Required]
[EnumDataType(enumType: typeof(TipoReciboCaja))]
public string TipoReciboCaja { get; set; }
[Required]
public int Numero { get; set; }
[Required]
public string Tercero { get; set; }
[Required]
public string AccionARealizar { get; set; }
[Required]
public DateTime FechaElaboracion { get; set; }
[Required]
public string CentroCostos { get; set; }
/// <summary>
/// este campo no sólo enlaza la cuenta donde se hace el abono o accion a realizar, sino también la forma de pago
/// </summary>
[Required]
public string CuentaIngresoDinero { get; set; }
[Required]
[Range(0, 999999999999)]
public double ValorPagado { get; set; }
}
and ReciboCajaBiz constructors and private members
private ICoDbProvider _reciboCajaService;
private ICoDbProvider _accionARealizarService;
private ICoDbProvider _centroCostosService;
private ICoDbProvider _terceroService;
private ICoDbProvider _tipoReciboCajaService;
public ReciboCajaBiz()
{
_reciboCajaService = new ReciboCajaService();
_accionARealizarService = new AccionARealizarService();
}
public ReciboCajaBiz(ICoDbProvider reciboCajaService = null, ICoDbProvider accionARealizarService = null, ICoDbProvider centroCostosService = null, ICoDbProvider terceroService = null, ICoDbProvider tipoReciboCajaService = null)
{
_reciboCajaService = reciboCajaService == null ? new ReciboCajaService() : reciboCajaService;
_accionARealizarService = accionARealizarService == null ? new AccionARealizarService() : accionARealizarService;
_centroCostosService = centroCostosService == null ? new CentroCostosService() : centroCostosService;
_terceroService = terceroService == null ? new TerceroService() : terceroService;
_tipoReciboCajaService = tipoReciboCajaService == null ? new TipoReciboCajaService() : terceroService;
}
Upvotes: 1
Views: 2434
Reputation: 12163
At a glance, your Moq expressions might not be matching as you expect.
Your trying to match on an object reference for your Exists() function, which means it will do an equality check on the object references - which won't match. You new'ing up two different objects.
_accionARealizarService.Exists(new AccionARealizarEntity(model))
See here for more info on Moq Matching Arguments
Change the Setup
expression of the mock so it is more generous to see if this is the problem.
You can use It.IsAny()
within the expression like.
accionARealizarService.Setup(m => m.Exists(It.IsAny<SiigoEntity>())).Returns(true);
Once that works you can get more specific with the It.Is()
expression, to do object property inspection.
Upvotes: 7
Reputation: 1135
The problem was using object references in the behavior set of the mock. I was using this:
accionARealizarService.Setup(m => m.Exists(new AccionARealizarEntity(s1))).Returns(true);
But that will cause the test to create an object and compare this object with the object sent to the Exists method so it can validate the behavior. This will cause a call to Equals
method and so it will always throw false.
To correctly validate the parameters sent to a mocked method, I should use this:
accionARealizarService.Setup(m => m.Exists(It.IsAny<CoEntity>())).Returns(true);
The It.IsAny<CoEntity>
statement will indicate the mocked method behavior to not compare against a specific instance of the object but to validate if the object is a CoEntity
.
I reached this conclusion and post this full answer based on @Ralph answer, which led me to the right path.
Upvotes: 2