0

This is a IValidationResult interface

public interface IValidationResult
{
    ICollection<IValidationError> Errors { get; }
    bool IsValid { get; }

    IValidationResult Add(IValidationError error);
    IValidationResult Add(string errorMessage);
    IValidationResult Add(params IValidationResult[] validationResults);
    IValidationResult Remove(IValidationError error);
}

I have this test method

[TestMethod]
public async Task ServicoDeveRetornarFalseCasoHajaErroNaCriacaoDoObjeto()
{
    // arrange
    var validation = Substitute.For<IValidationResult>();
    validation.IsValid.Returns(false);
    _contratoFactory.Build(ContratoValues.ContratoComEmpresaNula).Returns(validation);

    // act
    var result = await _contratoService.Create(ContratoValues.ContratoComEmpresaNula);

    // assert
    result.Success.Should().BeFalse();
}

The "validation" substitute is a Mock of IValidationResult. This Interface implements a property called IsValid that returns false is another property, that is a Collection contains any item.

My test method must verify that when

_contratoFactory.Build(any) 

is called, it returns a IValidationResult that isn't valid.

Then, the result of _contratoService.Create(any) should be false.

My mock is not working.

How can I fix it?

UPDATE - Add Create Implementation

public override async Task<IServiceOperationResult> Create(Contrato entity)
{
    var result = new ServiceOperationResult();
    try
    {
        if (entity == null)
        {
            throw new ArgumentNullException(typeof(Contrato).Name);
        }

        var validation = _contratoFactory.Build(entity);
        result.Add(validation);

        if (!result.Success)
        {
            return result;
        }

        return await base.Create(entity);
    }
    catch (ArgumentNullException ex)
    {
        result.Add(ex);
    }
    catch (Exception ex)
    {
        result.Add(ex);
    }

    return result;
}

UPDATE - 20/05/2015

Here is the implementation of IServiceOperationResult

public class ServiceOperationResult : IServiceOperationResult
{
    public ServiceOperationResult()
    {
        Errors = new Dictionary<string, string>();   
    }

    public IDictionary<string, string> Errors { get; }

    public bool Success => !Errors.Any();

    public void Add(string errorMessage)
    {
        if (errorMessage == null || errorMessage.Trim().Length == 0)
        {
            return;
        }

        Errors.Add(Guid.NewGuid().ToString(), errorMessage);
    }

    public void Add(IValidationResult validationResult)
    {
        if (validationResult == null)
        {
            return;
        }

        foreach (var validationError in validationResult.Errors)
        {
            Add(validationError);
        }
    }

    public void Add(IValidationError validationError)
    {
        if (string.IsNullOrEmpty(validationError?.Message) || 
            string.IsNullOrWhiteSpace(validationError.Message))
        {
            return;
        }

        Errors.Add(Guid.NewGuid().ToString(), validationError.Message);
    }

    public void Add(Exception exception)
    {
        if (exception == null)
        {
            return;
        }
        Add($"{nameof(exception)} - {exception.Message}{Environment.NewLine} - {exception.StackTrace}");
    }
}
Jedi31
  • 735
  • 1
  • 6
  • 22
  • You said that `IsValid` should return `true` however, you set it to return `false`: `validation.IsValid.Returns(false);` – Old Fox May 19 '16 at 22:12
  • I'm sorry. I've described it wrong. `IsValid` must return false. – Jedi31 May 19 '16 at 22:17
  • Please add the implementation of `Create` method.... – Old Fox May 19 '16 at 22:22
  • Please add the implementation of `ServiceOperationResult` – Old Fox May 19 '16 at 23:08
  • Is `_contratoFactory` a substitute in the test? Also make sure it is for an interface, or that the `Build` method is virtual if it is for a class. Are you getting an exception, or is the test just failing? – David Tchepak May 20 '16 at 03:20
  • Yeah, _contratoFactory in the test is a substitute for and interface, IContratoService. It has only the Build() method. The test is just failing. Expected false, but returns true. – Jedi31 May 20 '16 at 15:45

1 Answers1

1

The problem seems to stem from ServiceOperationResult.Add(IValidationResult validationResult):

    public void Add(IValidationResult validationResult)
    {
        if (validationResult == null) { return; }

        foreach (var validationError in validationResult.Errors)
        {
            Add(validationError);
        }
    }

This is relying on the validationResult.Errors collection, but you have not stubbed this out.

If you modify the test to something like the following it should pass:

        // arrange
        var validation = Substitute.For<IValidationResult>();
        validation.IsValid.Returns(false);
        validation.Errors.Returns (new List<IValidationError> ());
        validation.Errors.Add (new ValidationError { Message = "sample error" });
        _contratoFactory.Build(ContratoValues.ContratoComEmpresaNula).Returns(validation);
        // act ...

However from what I can see in this case I would suggest not faking IValidationResult, but using a real one, as the implementation depends on the real behaviour of the implementation of this interface.

This would make the test more like:

        // arrange
        var validation = new ValidationResult>();
        validation.Errors.Add (new ValidationError { Message = "sample error" }); 
        // I'm guessing for the real class `validation.IsValid` will now return `false`
        _contratoFactory.Build(ContratoValues.ContratoComEmpresaNula).Returns(validation);
        //act...
David Tchepak
  • 9,826
  • 2
  • 56
  • 68
  • I've tried it... But still fail. Seems like it when _factory.Build() returns, it not return a concrete ValidationResult, but a proxy, and de Error's collection is not loaded. If it has 0 itens, then Success method of IServiceOperationResult will return false... And the test fails... – Jedi31 May 23 '16 at 14:29
  • 1
    Example of a passing version of this test, using the first approach in this answer: https://gist.github.com/dtchepak/7e61de157040279ca6c5349dfa282a28 – David Tchepak May 23 '16 at 23:46