【问题标题】:How to write a xUnit test for the method which has another method inside it?如何为其中包含另一个方法的方法编写 xUnit 测试?
【发布时间】:2021-07-03 03:46:36
【问题描述】:

我想为 ValidatorCreateAsync 方法编写一个 xUnit 测试,方法如下:

public async Task<ValidationResult> ValidateCreateAsync(IJob job)
    {
        var validationResult = _validator.NullValidator(job.Payload, job.Module, job.EntityName);

        if (validationResult.ValidationResultEnum == ValidationResultEnum.Invalid)
            return validationResult;

        await _context.Jobs.InsertOneAsync(job as Job);

        return validationResult;
    }

这是我的 NullValidator 方法:

public ValidationResult NullValidator<T>(params T[] notNullEntities)
    {
        foreach (var entity in notNullEntities)
        {
            if (entity == null)
            {
                return new ValidationResult()
                {
                    ValidationResultEnum = ValidationResultEnum.Invalid,
                    ValidationResultMessageEnum = ValidationResultMessageEnum.NullProperty
                };
            }
        }

        return new ValidationResult()
        {
            ValidationResultEnum = ValidationResultEnum.Valid,
            ValidationResultMessageEnum = ValidationResultMessageEnum.NotNullFound
        };
    }

在 xUnit 测试中,如何编写 NullValidator 方法的设置以在以下测试中正常工作?

public class JobStoreTest
{

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

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

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

        

        //****************This code does not work here*****************
        _moqIValidator.Setup(_ => _.NullValidator(
            It.IsAny<Type[]>())
        ).Returns((Type[] y)
            => Task.FromResult(ValidationResult validation)); 

    }

    [Theory]
    [ClassData(typeof(JobClassesForTesting))]
    public async Task CreateAsync(IJob job)
    {
        var validationResult = await _jobStore.ValidateCreateAsync(job);

        ValidationResult expectedValidationResult = new ValidationResult()
        {
            ValidationResultEnum = ValidationResultEnum.Valid,
            ValidationResultMessageEnum = ValidationResultMessageEnum.NotNullFound
        };

        Assert.Equal(expectedValidationResult, validationResult);
    }
}

我希望第一次测试出错,其他测试应该通过。 这是我的测试场景(JobClassesForTesting):

public IEnumerator<object[]> GetEnumerator()
    {
        

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

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

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

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

【问题讨论】:

    标签: c# unit-testing asp.net-core xunit xunit.net


    【解决方案1】:

    job.Payload, job.Module, job.EntityName都是字符串成员,所以Type[]

    _moqIValidator
        .Setup(_ => _.NullValidator(It.IsAny<Type[]>()))
        .Returns((Type[] y) => Task.FromResult(ValidationResult validation)); 
    

    要匹配的类型错误

    这需要string[]

    其次,被模拟的成员不是异步的,所以不返回Task。因此没有理由使用Task.FromResult进行回调

    如果使用的IValidator 实现没有依赖关系,也没有使用实际类的负面影响,那么真的没有必要模拟它。使用实现本身

    例如

    private readonly Mock<IMongoDbContext> _moqIMongoDbContext;
    private readonly JobStore _jobStore;
    
    public JobStoreTest() {
        _moqIMongoDbContext = new Mock<IMongoDbContext>();        
        _jobStore = new JobStore(_moqIMongoDbContext.Object, new Validator());
    
        _moqIMongoDbContext
            .Setup(_ => _.Jobs.InsertOneAsync(
                It.IsAny<Job>(),
                It.IsAny<InsertOneOptions>(),
                It.IsAny<CancellationToken>())
            )
            .Returns((Job y, InsertOneOptions options, CancellationToken token)
                => Task.FromResult(y));
    
    }
    
    //...
    

    为了通过所有测试,需要修改测试数据以满足期望

    首先更新测试数据以包含预期结果

    public class JobClassesForTesting {
    
        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();
    }
    

    并重构测试以将预期结果作为参数以及断言

    [Theory]
    [ClassData(typeof(JobClassesForTesting))]
    public async Task CreateAsync(IJob job, ValidationResult expectedValidationResult) {
        //Act
        ValidationResult validationResult = await _jobStore.ValidateCreateAsync(job);
       //Assert
       Assert.Equal(expectedValidationResult, validationResult);
    }
    

    【讨论】:

    • moqIValidator.Setup( => _.NullValidator( It.IsAny()) ).Returns((string[] y) => 任务。 FromResult(ValidationResult 验证));谢谢,但它也不起作用
    • does not work mean 是什么?请说得更具体些。
    • 其实我只想在我的测试中看到 ValidateCreateAsync 的结果。我不知道该怎么做。
    • 这是在测试中用作验证器的对象。检查更新
    • 其余的将有ValidationResultEnum.ValidValidationResultMessageEnum.NotNullFound
    猜你喜欢
    • 2021-06-23
    • 2022-08-11
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    • 1970-01-01
    相关资源
    最近更新 更多