我是XUnit和Moq的新手。我有一个方法,它将字符串作为参数。如何使用XUnit处理异常。
[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException() {
//arrange
ProfileRepository profiles = new ProfileRepository();
//act
var result = profiles.GetSettingsForUserID("");
//assert
//The below statement is not working as expected.
Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}
待测方法
public IEnumerable<Setting> GetSettingsForUserID(string userid)
{
if (string.IsNullOrWhiteSpace(userid)) throw new ArgumentException("User Id Cannot be null");
var s = profiles.Where(e => e.UserID == userid).SelectMany(e => e.Settings);
return s;
}
答案 0 :(得分:101)
Assert.Throws表达式将捕获异常并声明类型。但是,您正在调用断言表达式之外的测试方法,从而使测试用例失败。
[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
//arrange
ProfileRepository profiles = new ProfileRepository();
// act & assert
Assert.Throws<ArgumentException>(() => profiles.GetSettingsForUserID(""));
}
如果遵循AAA,你可以将动作提取到它自己的变量
中[Fact]
public void ProfileRepository_GetSettingsForUserIDWithInvalidArguments_ThrowsArgumentException()
{
//arrange
ProfileRepository profiles = new ProfileRepository();
//act
Action act = () => profiles.GetSettingsForUserID("");
//assert
Assert.Throws<ArgumentException>(act);
}
答案 1 :(得分:28)
如果您确实希望对AAA非常严格,那么您可以使用xUnit中的Record.Exception来捕获Act阶段中的异常。
然后,您可以根据Assert阶段中捕获的异常进行断言。
可以在xUnits tests中看到这方面的一个例子。
[Fact]
public void Exception()
{
Action testCode = () => { throw new InvalidOperationException(); };
var ex = Record.Exception(testCode);
Assert.NotNull(ex);
Assert.IsType<InvalidOperationException>(ex);
}
由您决定要遵循的路径,xUnit提供的路径完全支持这两条路径。
答案 2 :(得分:2)
如果要坚持使用AAA,可以考虑采用以下方法:
// Act
Task act() => _handler.Handle(_request, CancellationToken.None);
// Assert
await Assert.ThrowsAsync<MyExpectedException>(act);
答案 3 :(得分:2)
我认为有两种方法可以处理我个人喜欢的这种情况。假设我有以下方法要测试
public class SampleCode
{
public void GetSettingsForUserID(string userid)
{
if (string.IsNullOrWhiteSpace(userid)) throw new ArgumentException("User Id
Cannot be null");
// Some code
}
}
我可以使用以下测试用例进行测试,确保在测试项目中添加 FluentAssertions nuget。
public class SampleTest
{
private SampleCode _sut;
public SampleTest()
{
_sut = new SampleCode();
}
[Theory]
[InlineData(null)]
[InlineData(" ")]
public void TestIfValueIsNullorwhiteSpace(string userId)
{
//Act
Action act= ()=> _sut.GetSettingsForUserID(userId);
// Assert
act.Should().ThrowExactly<ArgumentException>().WithMessage("User Id Cannot be null");
}
}
但我在这里发现了一个问题,空格和空是两种不同的东西。 c# 为空白提供 ArgumentException,为空引用提供 ArgumentNullException。
所以你可以像这样重构你的代码
public void GetSettingsForUserID(string userid)
{
Guard.Against.NullOrWhiteSpace(userid, nameof(userid));
}
这里你需要在你的代码项目中使用 Ardalis.GuardClauses nuget 并且测试用例将是这样的
[Fact]
public void TestIfValueIsNull()
{
//Act
Action act = () => _sut.GetSettingsForUserID(null);
//Assert
act.Should().ThrowExactly<ArgumentNullException>().WithMessage("*userId*");
}
[Fact]
public void TestIfValueIsWhiteSpace()
{
//Act
Action act= ()=> _sut.GetSettingsForUserID(" ");
//Assert
act.Should().ThrowExactly<ArgumentException>().WithMessage("*userId*");
}