我没有编写单元测试的经验,我开始使用它。
我的项目有一个数据访问层(带有nhibernate),我有一些存储库,由IoC容器注入到业务层的某些服务中。我想编写单元测试来测试服务(业务层)上的一些方法。我知道让Moq
来模拟存储库并避免命中数据库很重要。我想知道如何测试这种方法:
public bool AddNewProject(ProjectViewModel viewModel)
{
// _projectRepository is an interface: IProjectRepository, resolved by IoC container
if (_projectRepository.ExistsNumber(viewModel.Number))
{
Validation.AddError("Number", GlobalResource.DuplicatedNumber);
return false;
}
if (_projectRepository.GetTotalAvailable(viewModel.ItemId) > 0)
{
Validation.AddError("ItemId", GlobalResource.NotItemAvailable);
return false;
}
var project = Mapper.Map<Project>(viewModel);
project.Data = _projectRepository.GetData(viewModel.ItemId);
_projectRepository.Save(project);
viewModel.Id = project.Id;
return true;
}
我知道我必须编写至少三个单元测试,一个用于每个验证,一个用于成功。问题是在AutoMapper
配置中,我的IoC容器解析了AfterMap
事件的类型,样本:
config.CreateMap<ProjectViewModel, Project>()
.AfterMap((vm, p) => {
// it is necessary because nhibernate will save this relation
var cityRepository = container.Resolve<ICityRepository>();
p.City = cityRepository.Load(vm.CityId);
});
我在网上的某个地方看到没有必要在单元测试中使用IoC容器,我应该Moq
只需要我需要的方法(不确定它是否正确)。我是否必须定义内存存储库并在测试项目的ioc容器上注册它们?我很难测试,因为我需要重写所有的存储库(超过300个)。
Obs:很难改变,因为有超过300个实体使用Repository.Load
来对AfterMap
上的AutoMapper
事件进行关联。
这是我的单元测试:
[TestMethod]
public void Should_not_save_a_project_by_existent_number()
{
var viewModel = new ProjectViewModel();
viewModel.Code = "PJT";
viewModel.CityId = 1;
viewModel.ItemId = 1;
viewModel.Name = "This is a test";
// for the validation, I use this simulator in memory (in asp.net mvc I encapsulate the ModelState)
var validator = new MemoryValidation();
var projectMoqRepository = new Mock<IProjectRepository>();
// I will mock methods here...
var projectService = new ProjectService(projectMoqRepository.Object, validator);
// the ICityRepository is defined on the IoC, so when I call AddNewProject
// it will be resolved inside the AutoMapper context on the AfterMap event.
// it is not injected on the ProjectService ctor.
var result = projectService.AddNewProject(viewModel);
projectService.Validation["Number"].ShouldNotBeEmpty();
result.ShouldBeFalse();
}