如何使用 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));
不过,请考虑 Stop Using Assert.Throws in Your BDD Unit Tests,这表明您应该改用类似以下的内容:
var exception = Assert.Catch(() => validator.Validate(connectionModel));
Assert.NotNull(exception);
Assert.InstanceOf<ArgumentNullException>(exception);
理论认为后者更适合 Arrange-Act-Assert 布局,使您能够测试预期异常的多个方面。
首先,您不应该为业务逻辑验证抛出异常。例如,如果您正在验证用户输入,验证失败并不例外。异常不是为处理工作流而设计的。
相反 return 验证结果对象并让验证器的消费者决定如何 return/display 失败的结果给用户。
其次,在循环中抛出异常是没有意义的,因为第一个抛出的异常将 return 到堆栈的顶部并且将 "ignore" 其余的异常。
相反(如果仍想抛出异常)抛出一个 "specific" 异常,其中包含所有错误。
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);
但是,我再次建议重新考虑抛出异常并将 return 验证结果提供给消费者。
我有以下使用 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));
不过,请考虑 Stop Using Assert.Throws in Your BDD Unit Tests,这表明您应该改用类似以下的内容:
var exception = Assert.Catch(() => validator.Validate(connectionModel));
Assert.NotNull(exception);
Assert.InstanceOf<ArgumentNullException>(exception);
理论认为后者更适合 Arrange-Act-Assert 布局,使您能够测试预期异常的多个方面。
首先,您不应该为业务逻辑验证抛出异常。例如,如果您正在验证用户输入,验证失败并不例外。异常不是为处理工作流而设计的。
相反 return 验证结果对象并让验证器的消费者决定如何 return/display 失败的结果给用户。
其次,在循环中抛出异常是没有意义的,因为第一个抛出的异常将 return 到堆栈的顶部并且将 "ignore" 其余的异常。
相反(如果仍想抛出异常)抛出一个 "specific" 异常,其中包含所有错误。
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);
但是,我再次建议重新考虑抛出异常并将 return 验证结果提供给消费者。