Search code examples
c#unit-testingasp.net-corexunit

Why my expected and actual results are same but test fails?


Why my expected and actual result are same but test fails ?

This is my Test Class:

private readonly Mock<IMongoDbContext> _moqIMongoDbContext;
    private readonly JobStore _jobStore;

    public JobStoreTest()
    {
        _moqIMongoDbContext = new Mock<IMongoDbContext>();
        _jobStore = new JobStore(_moqIMongoDbContext.Object, new Validator.Validator());

        _moqIMongoDbContext
            .Setup(_ => _.Jobs.InsertOneAsync(
                It.IsAny<Job>(),
                It.IsAny<InsertOneOptions>(),
                It.IsAny<CancellationToken>())
            )
            .Returns((Job y, InsertOneOptions options, CancellationToken token)
                => Task.FromResult(y));

    }

    

    [Theory]
    [ClassData(typeof(JobClassesForTesting))]
    public async Task CreateAsync(IJob job, ValidationResult expectedValidationResult)
    {

        //Act
        ValidationResult validationResult = await _jobStore.ValidateCreateAsync(job);

        //Assert
        Assert.Equal(expectedValidationResult, validationResult);
    }

Here is my scenario (JobClassesForTesting):

   public class JobClassesForTesting : IEnumerable<object[]>
{
    public IEnumerator<object[]> GetEnumerator()
    {
        var valid = new ValidationResult()
        {
            ValidationResultEnum = ValidationResultEnum.Valid,
            ValidationResultMessageEnum = ValidationResultMessageEnum.NotNullFound
        };

        var invalid = new ValidationResult()
        {
            ValidationResultEnum = ValidationResultEnum.Invalid,
            ValidationResultMessageEnum = ValidationResultMessageEnum.NullProperty
        };

        yield return new object[] {
            new Job() {
                Payload = null,
                EntityName = "EntityNameTest1",
                Module = "ModuleTest1",
            },
            invalid
        };

        yield return new object[] {
            new Job() {
                Payload = "PayloadTest2",
                EntityName = "EntityNameTest2",
                Module = "ModuleTest2",
            },
            valid
        };

        yield return new object[] {
            new Job() {
                Payload = "PayloadTest3",
                EntityName = "EntityNameTest3",
                Module = "ModuleTest3",
            },
            valid
        };
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

Although my actual and expected results are the same but test fails. I added a picture of xUnit test result below. Here is my Error:

enter image description here

ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo


Solution

  • The reason for this is that objects are not compared by the values of their properties but by their reference.

    The quick fix for this is just to compare each property of your validation results:

    Assert.Equal(expectedValidationResult.ValidationResultEnum , validationResult.ValidationResultEnum );
    Assert.Equal(expectedValidationResult.ValidationResultMessageEnum , validationResult.ValidationResultMessageEnum );
    

    This is probably the route that I would go in this particular case because your ValidationResult class is simple and you probably aren't going to be testing it for equality throughout your codebase. This also has the advantage of Asserting both your message and result independently, so your test can tell you if you've accidentally assigned a message that doesn't make sense for a passing ValidationResult.

    Another option in c# 9 is record types which are compared by value instead of by reference. This is a good option for objects that are just blobs of data, like your ValidationResult objects.

    Yet another option for more complex scenarios there is IEquatable, which allows you to implement your own method for testing equality. I wouldn't bother with it in your case though.