XUnit Mock 没有像我期望的那样抛出异常
XUnit Mock not throwing exception like I would expect
我有以下使用 class 模拟的测试。当我尝试抛出异常时,它实际上从未抛出异常。它继续进行,就好像实际上正在调用该方法一样,我不确定为什么。
这是测试:
[Fact]
public async Task ReadResultSetShouldRetry()
{
// Arrange
_cosmosUtilWrapper.Setup(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(It.IsAny<FeedIterator>(), It.IsAny<ILogger>(), It.IsAny<CancellationToken>()))
.Throws(new Exception("It broke"));
var cosmosReadPolicy = new CosmosReadPolicy();
// Act
await Assert.ThrowsAsync<Exception>(async () => await CosmosRepository.ReadCosmosResultSetWithRetry<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, cosmosReadPolicy, CancellationToken.None));
// Assert
_cosmosUtilWrapper.Verify(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, default));
}
这是它正在调用的方法,我将其包装在重试策略中:
public static async Task<List<T>> ReadCosmosResultSetWithRetry<T>(
FeedIterator resultSet,
ILogger logger,
CosmosReadPolicy cosmosReadPolicy,
CancellationToken cancellationToken = default)
where T : class
{
CosmosUtilWrapper utilWrapper = new CosmosUtilWrapper();
var readCosmosResultSet = await cosmosReadPolicy.GetPolicy.ExecuteAsync(async () => await utilWrapper.ReadCosmosResultSet<T>(resultSet, logger, cancellationToken));
return readCosmosResultSet;
}
这是 CosmosUtilWrapper,下面是实际的 Cosmos Util class:
public class CosmosUtilWrapper
{
public virtual async Task<List<T>> ReadCosmosResultSet<T>(
FeedIterator resultSet,
ILogger logger,
CancellationToken cancellationToken = default)
where T : class
{
return await CosmosUtil.ReadCosmosResultSet<T>(resultSet, logger, cancellationToken);
}
}
这是在上面 class 中返回的实际静态 Util 方法。不得不这样做,因为这个 class 是静态的 class 并且对它们进行单元测试不是很有趣。
public static async Task<List<T>> ReadCosmosResultSet<T>(
FeedIterator resultSet,
ILogger logger,
CancellationToken cancellationToken = default)
where T : class
{
var foundDocuments = new List<T>();
while (resultSet.HasMoreResults)
{
using ResponseMessage responseMessage = await resultSet.ReadNextAsync(cancellationToken);
if (responseMessage.IsSuccessStatusCode)
{
using StreamReader streamReader = new StreamReader(responseMessage.Content);
using JsonTextReader textReader = new JsonTextReader(streamReader);
foundDocuments.AddRange((await JObject.LoadAsync(textReader, cancellationToken)).GetValue("Documents").ToObject<List<T>>());
}
else
{
throw new Exception($"Unable to read cosmos result set. Status code: {responseMessage.StatusCode}");
}
}
return foundDocuments;
}
最后,这是我在 运行 测试
时收到的消息
Message:
Assert.Throws() Failure
Expected: typeof(System.Exception)
Actual: (No exception was thrown)
这是因为ReadResultSetShouldRetry()
中的模型对象_cosmosUtilWrapper
从未在Task<List<T>> ReadCosmosResultSetWithRetry<T>
中使用过。
在方法 Task<List<T>> ReadCosmosResultSetWithRetry<T>
中,您初始化了一个新对象 CosmosUtilWrapper utilWrapper = new CosmosUtilWrapper();
。所以,这个对象和上面的对象不一样。
您可以使用以下代码从模型对象中获取对象:_cosmosUtilWrapper.Object
。从方法中删除静态时,在 class 的函数或构造函数中传递此对象。
例如:
public static async Task<List<T>> ReadCosmosResultSetWithRetry<T>(
FeedIterator resultSet,
ILogger logger,
CosmosReadPolicy cosmosReadPolicy,
CosmosUtilWrapper utilWrapper,
CancellationToken cancellationToken = default)
where T : class
{
var readCosmosResultSet = await cosmosReadPolicy.GetPolicy.ExecuteAsync(async () => await utilWrapper.ReadCosmosResultSet<T>(resultSet, logger, cancellationToken));
return readCosmosResultSet;
}
例如测试:
[Fact]
public async Task ReadResultSetShouldRetry()
{
// Arrange
_cosmosUtilWrapper.Setup(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(It.IsAny<FeedIterator>(), It.IsAny<ILogger>(), It.IsAny<CancellationToken>()))
.Throws(new Exception("It broke"));
var cosmosReadPolicy = new CosmosReadPolicy();
var utilWrapper = _cosmosUtilWrapper.Object;
// Act
await Assert.ThrowsAsync<Exception>(async () => await CosmosRepository.ReadCosmosResultSetWithRetry<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, cosmosReadPolicy, utilWrapper, CancellationToken.None));
// Assert
_cosmosUtilWrapper.Verify(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, default));
}
我有以下使用 class 模拟的测试。当我尝试抛出异常时,它实际上从未抛出异常。它继续进行,就好像实际上正在调用该方法一样,我不确定为什么。
这是测试:
[Fact]
public async Task ReadResultSetShouldRetry()
{
// Arrange
_cosmosUtilWrapper.Setup(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(It.IsAny<FeedIterator>(), It.IsAny<ILogger>(), It.IsAny<CancellationToken>()))
.Throws(new Exception("It broke"));
var cosmosReadPolicy = new CosmosReadPolicy();
// Act
await Assert.ThrowsAsync<Exception>(async () => await CosmosRepository.ReadCosmosResultSetWithRetry<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, cosmosReadPolicy, CancellationToken.None));
// Assert
_cosmosUtilWrapper.Verify(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, default));
}
这是它正在调用的方法,我将其包装在重试策略中:
public static async Task<List<T>> ReadCosmosResultSetWithRetry<T>(
FeedIterator resultSet,
ILogger logger,
CosmosReadPolicy cosmosReadPolicy,
CancellationToken cancellationToken = default)
where T : class
{
CosmosUtilWrapper utilWrapper = new CosmosUtilWrapper();
var readCosmosResultSet = await cosmosReadPolicy.GetPolicy.ExecuteAsync(async () => await utilWrapper.ReadCosmosResultSet<T>(resultSet, logger, cancellationToken));
return readCosmosResultSet;
}
这是 CosmosUtilWrapper,下面是实际的 Cosmos Util class:
public class CosmosUtilWrapper
{
public virtual async Task<List<T>> ReadCosmosResultSet<T>(
FeedIterator resultSet,
ILogger logger,
CancellationToken cancellationToken = default)
where T : class
{
return await CosmosUtil.ReadCosmosResultSet<T>(resultSet, logger, cancellationToken);
}
}
这是在上面 class 中返回的实际静态 Util 方法。不得不这样做,因为这个 class 是静态的 class 并且对它们进行单元测试不是很有趣。
public static async Task<List<T>> ReadCosmosResultSet<T>(
FeedIterator resultSet,
ILogger logger,
CancellationToken cancellationToken = default)
where T : class
{
var foundDocuments = new List<T>();
while (resultSet.HasMoreResults)
{
using ResponseMessage responseMessage = await resultSet.ReadNextAsync(cancellationToken);
if (responseMessage.IsSuccessStatusCode)
{
using StreamReader streamReader = new StreamReader(responseMessage.Content);
using JsonTextReader textReader = new JsonTextReader(streamReader);
foundDocuments.AddRange((await JObject.LoadAsync(textReader, cancellationToken)).GetValue("Documents").ToObject<List<T>>());
}
else
{
throw new Exception($"Unable to read cosmos result set. Status code: {responseMessage.StatusCode}");
}
}
return foundDocuments;
}
最后,这是我在 运行 测试
时收到的消息 Message:
Assert.Throws() Failure
Expected: typeof(System.Exception)
Actual: (No exception was thrown)
这是因为ReadResultSetShouldRetry()
中的模型对象_cosmosUtilWrapper
从未在Task<List<T>> ReadCosmosResultSetWithRetry<T>
中使用过。
在方法 Task<List<T>> ReadCosmosResultSetWithRetry<T>
中,您初始化了一个新对象 CosmosUtilWrapper utilWrapper = new CosmosUtilWrapper();
。所以,这个对象和上面的对象不一样。
您可以使用以下代码从模型对象中获取对象:_cosmosUtilWrapper.Object
。从方法中删除静态时,在 class 的函数或构造函数中传递此对象。
例如:
public static async Task<List<T>> ReadCosmosResultSetWithRetry<T>(
FeedIterator resultSet,
ILogger logger,
CosmosReadPolicy cosmosReadPolicy,
CosmosUtilWrapper utilWrapper,
CancellationToken cancellationToken = default)
where T : class
{
var readCosmosResultSet = await cosmosReadPolicy.GetPolicy.ExecuteAsync(async () => await utilWrapper.ReadCosmosResultSet<T>(resultSet, logger, cancellationToken));
return readCosmosResultSet;
}
例如测试:
[Fact]
public async Task ReadResultSetShouldRetry()
{
// Arrange
_cosmosUtilWrapper.Setup(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(It.IsAny<FeedIterator>(), It.IsAny<ILogger>(), It.IsAny<CancellationToken>()))
.Throws(new Exception("It broke"));
var cosmosReadPolicy = new CosmosReadPolicy();
var utilWrapper = _cosmosUtilWrapper.Object;
// Act
await Assert.ThrowsAsync<Exception>(async () => await CosmosRepository.ReadCosmosResultSetWithRetry<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, cosmosReadPolicy, utilWrapper, CancellationToken.None));
// Assert
_cosmosUtilWrapper.Verify(x => x.ReadCosmosResultSet<CosmosRepositoryTests>(_mockFeedIterator.Object, _logger, default));
}