sách gpt4 ai đã đi

entity-framework - 如何构建工作单元/服务层/存储库,以便它们与 DI (Unity) 和 Moq 一起进行单元测试

In lại 作者:行者123 更新时间:2023-12-04 21:42:59 25 4
mua khóa gpt4 Nike

我有一个 MVC 应用程序(EF6、SQL Server CE 4),我最近对其进行了重构以添加 UnitOfWork类和一个服务层(这样我可以为每个请求使用一个 DbContext,并成功进行事务)。

以前,我使用 Unity 将存储库注入(inject) Controller 。我的单元测试(针对 Controller )很容易设置——我只是模拟了每个存储库,并将它们传递给 Controller 构造函数。

重构后,我现在使用 Unity 注入(inject)服务层(到 Controller )和 UnitOfWork (进入服务层)。服务层现在实例化每个存储库,通过传递 UnitOfWork.DbContext到存储库的构造函数。

在我的单元测试中,我试图模拟 UnitOfWork , 和 ServiceLayer(并将模拟的 UnitOfWork 对象传递给 ServiceLayer 的构造函数)。但是,测试失败,说“TestFixtureSetup 在 ControllerTest 中失败”。

我认为这是由于我试图通过 UnitOfWork模拟到 ServiceLayer 模拟中,因此将不胜感激有关如何正确执行此操作的任何指导。

下面的相关代码片段。

工作单位

public interface IUnitOfWork:IDisposable
{
void Save();
IDSMContext Context { get; }
}

public class UnitOfWork : IUnitOfWork, IDisposable
{
private IDSMContext _context;

public UnitOfWork()
{
_context = new IDSMContext();
}

public IDSMContext Context
{
get {return _context;}
}

public void Save()
{
_context.SaveChanges();
}

private bool disposed = false;

protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
_context.Dispose();
}
}
this.disposed = true;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}

服务层
public interface IService
{
// Repositories
IUserRepository Users { get; }
IUserTeamRepository UserTeams { get; }
IPlayerRepository Players { get; }
IGameRepository Games { get; }
IUserTeam_PlayerRepository UserTeamPlayers { get; }

void Save();
}

public class Service: IService, IDisposable
{
private IUnitOfWork _unitOfWork;
private IUserRepository _userRepository;
private IUserTeamRepository _userTeamRepository;
private IPlayerRepository _playerRepository;
private IGameRepository _gameRepository;
private IUserTeam_PlayerRepository _userTeamPlayerRepository;

public Service(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
initialiseRepos();
}

private void initialiseRepos(){
_userRepository = _userRepository ?? new UserRepository(_unitOfWork.Context);
_userTeamRepository = _userTeamRepository ?? new UserTeamRepository(_unitOfWork.Context);
_playerRepository = _playerRepository ?? new PlayerRepository(_unitOfWork.Context);
_gameRepository = _gameRepository ?? new GameRepository(_unitOfWork.Context);
_userTeamPlayerRepository = _userTeamPlayerRepository ?? new UserTeam_PlayerRepository(_unitOfWork.Context);
}

public IUserRepository Users { get { return _userRepository; } }
public IUserTeamRepository UserTeams { get { return _userTeamRepository; } }
public IPlayerRepository Players { get { return _playerRepository; } }
public IGameRepository Games { get { return _gameRepository; } }
public IUserTeam_PlayerRepository UserTeamPlayers { get { return _userTeamPlayerRepository; } }

public void Save()
{
_unitOfWork.Save();
}

Unity 容器实例设置
    Instance.RegisterType(new PerThreadLifetimeManager())
.RegisterType();

Controller 构造器
public GameController(IService service)
{
_service = service;
}

测试构造函数
_mockUnitOfWork = new Mock();
_mockServiceLayer = new Mock(_mockUnitOfWork.Object); //this line fails

测试 Controller 方法
GameController Controller = new GameController(_mockServiceLayer.Object);

1 Câu trả lời

如果要测试GameController的方法您只需要模拟/ stub 该类的依赖项。只需这样做:

_mockServiceLayer = new Mock();
_controller = new GameController(_mockServiceLayer.Object);

当你测试 Controller 时,你不应该担心服务的依赖关系。 UnitOfWork 永远不会暴露在你的服务之外,所以在测试 Controller 时不要担心它。在您的测试中,您现在可以设置在您的 上调用的方法的预期。服务 ,例如验证 Save 是否被调用一次(如果您正在测试服务,那么您会担心 IService.Save 在 IUnitOfWork 的模拟上调用 Save!):
_mockServiceLayer.Verify(s=> s.Save(), Times.Once()); 

您会发现的问题是您的服务类没有从存储库中抽象出 Controller ,因为您的 Controller 将通过 IService 中的属性获取存储库。并直接查询存储库。因此,如果您想测试您的 Controller 方法,您仍然需要模拟存储库,执行以下操作:
//Initialization before each test:
_mockUserRepo = new Mock();
//...other repositories
_mockServiceLayer = new Mock();
_mockServiceLayer.Setup(s => s.Users).Returns(_mockUserRepo.Object);
//... setup properties in IService for other repositories
_controller = new GameController(_mockServiceLayer.Object);

//In some test:
var user = new User();
_mockUserRepo.Setup(s => s.Get(123)).Returns(user);

call some controller method and make sure returned model is "user"

这样,您可能会发现自己配置了一些存储库和 UnityOfWork 返回的期望和数据,只是为了测试 Controller 中的方法!更不用说您的 Controller 类实际上取决于您的存储库,而不仅仅是服务。

另一种方法是,如果您的服务类包含更高级别的方法,例如 获取用户 , 创建用户 hoặc 添加用户到团队 (可能有多个服务与密切相关的方法)。然后,该服务将屏蔽 Controller 检索/发送数据到存储库和使用 UnitOfWork。

这样在你的测试中你只需要模拟 IService .
例如,典型“GET”操作的测试可能如下所示:
//Arrange
var user = new User();
_mockServiceLayer.Setup(s => s.GetUser(123)).Returns(user);

//Act
var viewResult = _controller.GetUser(123) as ViewResult;

//Assert
Assert.AreEqual(user, viewResult.Model);

希望这将有助于澄清一些事情!

关于entity-framework - 如何构建工作单元/服务层/存储库,以便它们与 DI (Unity) 和 Moq 一起进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21724057/

25 4 0
行者123
Hồ sơ cá nhân

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá Didi Taxi miễn phí
Mã giảm giá Didi Taxi
Giấy chứng nhận ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com