我继承了一个asp.net web api项目,遵循正常的控制器-->服务-->存储库架构。这个项目没有单元测试,我正在尝试对其进行改造。
这个项目中的典型服务是这样的:
public class TeamService : ITeamService
{
private readonly ITeamRepository _teamRepository;
private readonly ILogger<ITeamService> _logger;
private readonly IMapper _mapper;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUserRepository _userRepository;
private readonly IPlayerRepository _playerRepository;
public TeamService(ITeamRepository teamRepository, ILogger<ITeamService> logger,IMapper mapper, IHttpContextAccessor httpContextAccessor, IUserRepository userRepository, IPlayerRepository playerRepository)
{
_teamRepository = teamRepository;
_logger = logger;
_mapper = mapper;
_httpContextAccessor = httpContextAccessor;
_userRepository = userRepository;
_playerRepository = playerRepository;
}
//the rest of the service....
}
这里我们有六个存储库必须传递到此服务中。项目中没有任何代码创建过
TeamRepository
或 TeamService
。相反,TeamController
看起来像:
[Route("api/[controller]")]
[ApiVersion("1.0")]
[ApiController]
public class TeamController : ControllerBase
{
private readonly ITeamService _teamService;
private readonly ISchoolService _schoolService;
public TeamController(ITeamService teamService, ISchoolService schoolService)
{
_teamService = teamService;
_schoolService = schoolService;
}
//the rest of the controller....
}
WebApi 自动创建此类并将所需的
TeamService
传递到构造函数中。
在网络应用程序设置中,我们有
builder.Services.RegisterRepository(Assembly.Load("MyNamespace.Repository"));
builder.Services.RegisterServices(Assembly.Load("MyNamespace.Service")
我猜 WebApi 会进行一些反射来加载这些程序集,查找所有服务和存储库的类型,当有人点击 api 端点时,WebApi 通过将构造函数参数匹配来创建所需的对象(服务、存储库和控制器)实现这些接口并用它们创建控制器的已知类型。
我的问题是你如何用Moq做类似的事情?我想为
TeamService
编写一个单元测试,并且必须手动创建所有模拟存储库(每个存储库本身都有需要的参数),这似乎非常乏味。我希望有类似的说法
MyNamespace.Mock.Services
和MyNamespace.Mock.Repositories
var service = Mock.CreateByReflection<TeamService>()
service.TestSomeMethod()
模拟 WebApi 方便的自动对象创建的 Moq 方式是什么?
我继承了一个asp.net web api项目,遵循普通的controller-->service-->repository架构
是的,不幸的是,这很常见,但可能会给您带来问题。这不是你的错,因为你继承了代码库,我只是指出这一点,因为它可能会导致维护方面的摩擦,包括添加自动化测试。在架构层面,这种实现的问题在于它违反了依赖倒置原则。
这听起来可能很抽象,但具有实际意义。出现的一个常见问题与测试有关,测试编写者反复遇到“如何模拟”某些东西的问题,因为抽象依赖于难以测试的实现细节。
我指出这一点是因为,如果您在向此代码库添加测试的过程中感到“测试很糟糕”,那么错误在于应用程序架构,而不是单元测试。
总而言之,代码库展示了依赖注入构造函数的疯狂。再说一遍,这不是你的错,而是另一个避免继续前进的代码味道。
测试确实不应该执行以下操作,但在遗留代码场景中,您可能需要考虑建立一个 auto-mocking 容器 来进行测试。例如,您可以出于此目的将起订量和温莎城堡结合起来。虽然您可以使用与生产代码相同的依赖注入容器,但您不必这样做。
短语 auto-mocking 的适用范围足够广泛,网络搜索可以为您提供比上面链接更多的示例。
需要明确的是,问题和建议的解决方案与 Moq 或任何其他基于反射的 Test Double 库关系不大。这是与依赖项的管理和组合相关的问题,与定义测试替身的问题不同。