简体   繁体   English

如何使用XUnit对每个验证错误进行单元测试引发的异常

[英]How to unit test an exception throwing for each validation error using XUnit

I have the following method which uses FluentValidation to validate a ConnectionModel : 我有以下使用FluentValidation验证ConnectionModel

    internal static bool Validate(ConnectionModel connectionModel)
    {
        var validator = new ConnectionModelValidator();

        var result = validator.Validate(connectionModel);

        if (result.IsValid) return true;

        foreach (var failure in result.Errors)
            throw new ArgumentNullException(failure.ErrorMessage);

        return false;
    }

How can I unit test, using XUnit, the following bits which should throw ArgumentNullException for each validation error: 如何使用XUnit对以下位进行单元测试,这些位应针对每个验证错误抛出ArgumentNullException:

        foreach (var failure in result.Errors)
            throw new ArgumentNullException(failure.ErrorMessage);

        return false;

Here is what I tried so far: 这是我到目前为止尝试过的:

    public void Validate_ShouldThrowArgumentNullExceptionIfConnectionModelHasEmptyProperty()
    {
        var connectionModel = new ConnectionModel
        {
            JumpHostname = "10.1.1.1",
            JumpUsername = "test",
            SaaHostname = "test",
            SaaPassword = "test",
            SaaUsername = "test",
            SidePassword = "test",
            SideServiceName = "test",
        };
        var validator = new ConnectionModelValidator();

        var result = validator.Validate(connectionModel);

        Assert.NotEmpty(result.Errors);

    }

but this scenario only covers Errors not being empty. 但是此方案仅涵盖错误不为空的情况。

You could test that with: 您可以使用以下方法进行测试:

Assert.Throws<ArgumentNullException>(() => validator.Validate(connectionModel));

Consider Stop Using Assert.Throws in Your BDD Unit Tests , though, which suggests you should instead use something like: 不过,请考虑停止在BDD单元测试中使用Assert.Throws ,这表明您应该改用以下方法:

var exception = Assert.Catch(() => validator.Validate(connectionModel));
Assert.NotNull(exception);
Assert.InstanceOf<ArgumentNullException>(exception);

The theory being that the latter better fits the Arrange-Act-Assert layout and enables you to test multiple aspects of the expected exception. 从理论上讲,后者可以更好地适合“安排-行为-声明”布局,并使您能够测试预期异常的多个方面。

First, you shouldn't throw an exception for business logic validations. 首先,您不应为业务逻辑验证抛出异常。 For example if you are validating user input, failed validation is not exceptional. 例如,如果您要验证用户输入,则验证失败并非例外。 Exceptions wasn't designed for handling a workflow. 异常不是为处理工作流而设计的。
Instead return validation result object and leave consumer of the validator to decide what how to return/display failed results to the user. 而是返回验证结果对象,并让验证器的使用者决定如何向用户返回/显示失败的结果。

Second, throwing exceptions in the loop make no sense, because first thrown exception will return to the top of the stack and will "ignore" rest of exceptions. 其次,在循环中抛出异常没有意义,因为第一个抛出的异常将返回堆栈的顶部,并且将“忽略”其余的异常。

Instead (if still want to throw exceptions) throw one and "specific" exception with all errors included in it. 而是(如果仍然要抛出异常)则抛出一个“特定”异常,其中包含所有错误。

public class InvalidConnectionModelException : Exception
{
    public string[] ErrorMessages { get; }

    public InvalidConnectionModelException(string[] errorMessages)
    {
        ErrorMessages = errorMessages;
    }
}

// Throw own exception
internal static bool Validate(ConnectionModel connectionModel)
{
    var validator = new ConnectionModelValidator();
    var result = validator.Validate(connectionModel);

    if (result.IsValid) 
    {
        return true;
    }

    var errorMessages = result.Errors.Select(error => error.ErrorMessage).ToArray();
    throw new InvalidConnectionModelException(errorMessages);
}

With custom exception validation can be tested simpler 使用自定义异常验证可以测试更简单

var invalidModel = new ConnectionModel { ... };

var validator = new ConnectionModelValidator();
Action validate = () => validator.Validate(invalidModel);

Assert.Throws<InvalidConnectionModelException>(validate);

But again, I would suggest reconsider throwing exception and would return validation result to the consumer. 但是,我再次建议重新考虑引发异常并将验证结果返回给使用者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM