我正在编写一些单元测试,并且遇到了一段感觉像代码味道的代码。
基本上我有一个Web Api。它收到一个传入的请求' SomeRequest':
public class SomeRequest
{
public string Name { get; set; }
public IEnumerable<int> RequestedDataIds { get; set; }
}
作为我测试的一部分。我需要确保所有这些&#39; RequestedDataIds&#39;是有效的。我有一个方法调用系统的另一部分,它返回一个有效的&#39; SomeData&#39;对象。 &#39; SomeData&#39;对象包含要验证的ID:
public class SomeData
{
public int Id { get; set; } //Id to validate against
public string Name { get; set; }
}
我正在测试的系统看起来像这样:
public void Execute(RequestA request)
{
var validDataIds = _someService.GetValidEntities().Select(x => x.Id).ToList();
var invalidRequestIds = request.RequestedDataIds.Where(requestedId => !validDataIds.Contains(requestedId));
if (invalidRequestIds.Any())
{
throw new SomeException("Error");
}
//Carry on as normal
}
我的问题是。是否有最佳实践或任何方式让AutoFixture让这两个集合相互交互,以便我可以进行测试:
这是我目前对这个问题的尝试。我只是不喜欢它。
1 - 确保不同的id引发异常
[Test]
public void Test1()
{
_fixture = new Fixture();
var request = _fixture.Create<SomeRequest>();
var dataEnitities = _fixture.CreateMany<SomeData>();
var maxDataEntityId = dataEnitities.Select(x => x.Id).Max();
request.RequestedDataIds = new List<int> {maxDataEntityId + 1};
_someService.GetValidEntities.Returns(dataEnitities);
//Ensure exception is thrown
}
2 - 确保相同的ID以防止异常
[Test]
public void Test1()
{
_fixture = new Fixture();
var request = _fixture.Create<SomeRequest>();
var dataEnitities = _fixture.CreateMany<SomeData>();
request.RequestedDataIds = dataEnitities.Select(x => x.Id);
_someService.GetValidEntities.Returns(dataEnitities);
//Ensure no exception is thrown
}
注意 - 此代码大大减少了实际实现。因此,请不要关心它的外观和实施方式。
答案 0 :(得分:1)
是的,这是代码味道。您的测试是有效的,但它们可能很简单。 AutoFixture是一个很好的工具,但在这种特殊情况下,我认为你不需要它。
首先,尝试尽可能简化Execute()方法。它或多或少地在Presentation / Controller / Api层中使用,因此尽可能保持精简。不要任何胖控制器。
你真的只需要调用服务方法。
public void Execute(RequestA request)
{
_someService.ValidateEntities(request);
}
注意方法名称。它没有返回任何东西。 您的服务可以是:
public interface ISomeService
{
void ValidateEntities(RequestA request);
}
此实现将从基础数据源或服务返回ValidDataEntities。
var validDataIds = GetValidEntities().Select(x => x.Id);
我假设您从某种存储库或其他服务获取实体列表。
将您的逻辑推送到更多域/ poco对象。
创建一个简单的POCO类,即EntityValidator,它接受您的Request和validDataIds。 你可以单独测试这个POCO类,而不必使用AutoFixture或任何模拟。
public class EntityValidator
{
public void Validate(IEnumerable<int> validEntityIds, RequestA request)
{
var invalidRequestIds = request.RequestedDataIds.Where(requestedId => !validEntityIds.Contains(requestedId));
if (invalidRequestIds.Any())
{
throw new SomeException("Error");
}
}
}
您的单元测试很简单,您可以使用测试框架方法,即NUnit中的.Thorws测试异常情况。