У меня есть приложение MVC (EF6, SQL Server CE 4), которое я недавно реорганизовал для добавления класса UnitOfWork
и уровень обслуживания (чтобы я мог использовать один DbContext
за запрос и успешно выполнять транзакции).Как структурировать unitofwork/сервисный уровень/репозиторий, чтобы они работали с DI (Unity) и Moq для модульного тестирования
Раньше я использовал Unity для ввода репозиториев в контроллер. Мои модульные тесты (для контроллеров) были просты в настройке - я просто издевался над каждым репозиторием и передавал их в конструктор контроллера.
После рефакторинга теперь я использую Unity для ввода уровня обслуживания (контроллеру) и UnitOfWork
(в сервисный уровень). Теперь сервисный уровень создает экземпляр каждого репозитория, передавая UnitOfWork.DbContext
конструктору репозитория.
В моих модульных тестах я пытаюсь высмеять UnitOfWork
и ServiceLayer (и передать объект UnitOfWork
в конструктор ServiceLayer). Тем не менее, тесты терпят неудачу, говоря, что «TestFixtureSetup не удалось в ControllerTest».
Я предполагаю, что это связано с тем, как я пытаюсь передать UnitOfWork
макет в манере ServiceLayer, так что по достоинству оцените любые рекомендации о том, как это сделать правильно.
Соответствующие фрагменты кода ниже.
UnitOfWork
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);
}
}
Service Layer
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 Setup
Instance.RegisterType<IService, Service>(new PerThreadLifetimeManager())
.RegisterType<IUnitOfWork, UnitOfWork>();
Метод контроллера Конструктор
public GameController(IService service)
{
_service = service;
}
Test Constructor
_mockUnitOfWork = new Mock<IUnitOfWork>();
_mockServiceLayer = new Mock<IService>(_mockUnitOfWork.Object); //this line fails
Controller Test
GameController Controller = new GameController(_mockServiceLayer.Object);
Я пытался понять, как использовать сервисный уровень - и это произошло со мной. Я бы лучше переместил все методы репозитория на уровень сервиса, как вы предлагаете (я просто не обходил к тому же, поскольку первая проблема, на которую я наткнулся, была неспособна работать с Unit Tests). Одна из проблем заключается в том, что уровень сервиса теперь будет содержать множество и множество методов. Вы предложили бы иметь несколько уровней обслуживания? – jag
Я бы группировал связанные методы в разные службы. Вы можете в конечном итоге, например, с помощью UserService, TeamService и PlayerService. Таким образом, у вас будет слой _service_, состоящий из нескольких сервисных интерфейсов/классов. Вероятно, у вас уже есть аналогичная группировка с классами Controller –