从单元测试的角度来看,我是否应该在一般开发和代码可读性方面放置保护子句来检查注入到控制器的空参数?
还是我应该依靠ASP.NET Core框架,如果一切都正确配置(例如DI容器,模型绑定和其他配置),它将不会传递null或无效参数?
这里是不带保护子句的示例控制器:
[ApiController]
public class HomeController : ControllerBase
{
private readonly IRepository _repository;
private readonly IMapper _mapper;
private readonly string _message;
public HomeController(IRepository repository, IMapper mapper, string message)
{
_liveEventsRepository = repository;
_mapper = mapper;
_message = message;
}
[HttpGet]
public IActionResult GetSomeData([FromQuery]QueryParameters parameters)
{
var result = _repository.GetData(parameters);
var items = _mapper.Map<IEnumerable<MyItemDto>>(result.MyItems);
return Ok(new
{
items,
result.TotalItemsCount
});
}
}
如果我添加如下保护条款:
[ApiController]
public class HomeController : ControllerBase
{
private readonly IRepository _repository;
private readonly IMapper _mapper;
private readonly string _message;
public HomeController(IRepository repository, IMapper mapper, string message)
{
if (repository == null)
throw new ArgumentNullException("repository");
if (mapper == null)
throw new ArgumentNullException("mapper");
if (String.IsNullOrWhiteSpace(message))
throw new ArgumentException("text");
_liveEventsRepository = repository;
_mapper = mapper;
_message = message;
}
[HttpGet]
public IActionResult GetSomeData([FromQuery]QueryParameters parameters)
{
if (parameters == null)
throw ArgumentNullException("parameters");
var result = _repository.GetData(parameters);
var items = _mapper.Map<IEnumerable<MyItemDto>>(result.MyItems);
return Ok(new
{
items,
result.TotalItemsCount
});
}
}
这会给我的代码库增加任何价值吗?还是考虑到基础框架基础结构并假设一切都已正确设置,我是否应该完全跳过ASP.NET Core控制器中的保护子句?
从单元测试的角度来看,我是否应该通过传递空/无效参数来测试控制器构造函数和操作,还是不需要的开销?
答案 0 :(得分:1)
对此将有一个答案。这里不一定有正确或错误的答案。您当然可以相信,控制器将注入所需的任何依赖项。如果不能,则将引发异常。
但是,出于两个原因,我仍然倾向于使用防护装置。首先,我坚决支持一致性。如果您开始区分这东西需要警卫,而另一件事则不需要,那么不可避免地,您将不会总是考虑增加警卫,而会将他们留在应有的位置。如果您一直都只是添加警卫,那么您的行为是一致的,并且您不会错过任何事情。
第二,在进行单元测试时,您将负责(在某种程度上)填充依赖项,因此保护子句可用于对测试代码进行完整性检查。如果您忘记满足某个依赖关系,那么您将确切地知道代码为什么会失败,而不是真正尝试使用该依赖关系时,便会在代码稍后引起一些随机错误。
简而言之,这是这些成本效益结论之一。添加保护子句需要花费多少精力?如果确实不需要它们,它们当然不会伤害任何东西,但是,在那里存在可以带来什么好处?好的,一致性和健全性检查实际上是非常有价值的,当涉及到跟踪错误和仅维护代码时。
对于它的价值,您应该真正使用throw表达式,因为它更干净,更容易,这使得这样做的决定变得更加容易:
_liveEventsRepository = repository ?? throw new ArgumentNullException(nameof(repository));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
_message = !string.IsNullOrWhiteSpace(message) ? message : throw new ArgumentException("Value must not be null or whitespace.", nameof(message));