繁体   English   中英

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

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

我有以下使用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;
    }

如何使用XUnit对以下位进行单元测试,这些位应针对每个验证错误抛出ArgumentNullException:

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

        return false;

这是我到目前为止尝试过的:

    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);

    }

但是此方案仅涵盖错误不为空的情况。

您可以使用以下方法进行测试:

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

不过,请考虑停止在BDD单元测试中使用Assert.Throws ,这表明您应该改用以下方法:

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

从理论上讲,后者可以更好地适合“安排-行为-声明”布局,并使您能够测试预期异常的多个方面。

首先,您不应为业务逻辑验证抛出异常。 例如,如果您要验证用户输入,则验证失败并非例外。 异常不是为处理工作流而设计的。
而是返回验证结果对象,并让验证器的使用者决定如何向用户返回/显示失败的结果。

其次,在循环中抛出异常没有意义,因为第一个抛出的异常将返回堆栈的顶部,并且将“忽略”其余的异常。

而是(如果仍然要抛出异常)则抛出一个“特定”异常,其中包含所有错误。

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);
}

使用自定义异常验证可以测试更简单

var invalidModel = new ConnectionModel { ... };

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

Assert.Throws<InvalidConnectionModelException>(validate);

但是,我再次建议重新考虑引发异常并将验证结果返回给使用者。

暂无
暂无

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

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