我正在尝试对基于HTML模板异步向用户发送电子邮件的Api控制器进行单元测试。
控制器操作:
public async Task<IHttpActionResult> Email(int id)
{
var company = _unitOfWork.Companies.GetCompany();
var repairTypes = _unitOfWork.RepairTypes.GetRepairTypes().ToList();
var repair = _unitOfWork.Repairs.GetRepair(id);
if (repair == null || company == null || !repairTypes.Any() || !repair.Devices.Any())
return NotFound();
if (repair.Customer.Email == null)
{
return BadRequest("No customer email");
}
try
{
var viewModel = new ReceiptViewModel(company, repair, false, false);
viewModel.AssignRepairTypes(repairTypes);
await Core.Utilities.Email
.SendEmail(repair.Customer.Email, viewModel.GetReceiptEmailBody(), "Your Repair Summary");
}
catch (Exception exception)
{
return BadRequest(exception.Message);
}
return Ok();
}
查看从磁盘读取模板的模型:
public class ReceiptViewModel
{
public Company Company { get; set; }
public Repair Repair { get; }
public bool ShowLogo { get; private set; }
public bool AutoPrint { get; private set; }
public ReceiptViewModel(Company company, Repair repair, bool showLogo, bool autoPrint)
{
Company = company;
Repair = repair;
ShowLogo = showLogo;
AutoPrint = autoPrint;
if (Company.LogoPath.Contains("~"))
{
Company.LogoPath = Company.LogoPath.Remove(0, 1);
}
}
public void AssignRepairTypes(IEnumerable<RepairType> repairTypes)
{
Repair.Devices.ForEach(d => d.RepairType =
repairTypes.SingleOrDefault(rt => rt.Id == d.RepairTypeId));
}
public string GetReceiptEmailBody()
{
var server = HttpContext.Current.Server;
// Generate the email body from the template file.
var emailHtmlBody = new TemplateService();
var path = server.MapPath("~/Views/Repairs/ReceiptTemplate.cshtml");
var readAllText = File.ReadAllText(path);
return emailHtmlBody.Parse(readAllText, this, null, "RepairEmail");
}
}
测试类:
[TestClass]
public class RepairsControllerTests
{
private RepairsController _controller;
private Mock<ICompanyRepository> _mockCompanyRepository;
private Mock<IRepairRepository> _mockRepairRepository;
private Mock<IRepairTypeRepository> _mockRepairTypeRepository;
[ClassInitialize]
public static void Init(TestContext context)
{
Mapper.Initialize(c => c.AddProfile<MappingProfile>());
}
[TestInitialize]
public void TestInitialize()
{
HttpContext.Current = new HttpContext(new HttpRequest(null, "http://test.org", null), new HttpResponse(null));
_mockCompanyRepository = new Mock<ICompanyRepository>();
_mockRepairRepository = new Mock<IRepairRepository>();
_mockRepairTypeRepository = new Mock<IRepairTypeRepository>();
var mockUoW = new Mock<IUnitOfWork>();
mockUoW.SetupGet(u => u.Companies).Returns(_mockCompanyRepository.Object);
mockUoW.SetupGet(u => u.Repairs).Returns(_mockRepairRepository.Object);
mockUoW.SetupGet(u => u.RepairTypes).Returns(_mockRepairTypeRepository.Object);
_controller = new RepairsController(mockUoW.Object);
_controller.MockCurrentUser("1", "user1@domain.com");
}
//All other tests..
[TestMethod]
public async Task Email_ValidRequest_ShouldReturnOk()
{
var company = new Company() { Name = "Test", Email = "a@a.com", Id = 1, City = "T", Country = "C", LogoPath = "", PhoneNumber = "", PostCode = "", Street = "", TnC = "" };
var repairTypes = new List<RepairType>() { new RepairType() { Id = 1, Name = "Test" } };
var devices = new List<Device>() { new Device() { Id = 1, SerialNumber = "1", RepairTypeId = 1 } };
var repair = new Repair
{
Id = 1,
Customer = new Customer() { Email = "test@tm.com" },
Devices = devices
};
_mockRepairRepository.Setup(r => r.GetRepair(1)).Returns(repair);
_mockCompanyRepository.Setup(r => r.GetCompany()).Returns(company);
_mockRepairTypeRepository.Setup(r => r.GetRepairTypes()).Returns(repairTypes);
var result = await _controller.Email(1);
result.Should().BeOfType<OkResult>();
}
}
所以问题是Email_ValidRequest_ShouldReturnOk()
测试失败,因为Server.Mappath
正在返回null
,因此未加载模板。正如您所看到的,我尝试初始化当前的HttpContext
,但Server.Mappath
仍无效。我还尝试使用Server.Mappath
替换Path.Combine
来电,使用当前的应用域来确定路径。这也不起作用,因为应用程序域指向Debug
文件夹。
在对此问题进行了一些研究之后,我意识到不推荐使用Server.MapPath
,因为它引入了另一个依赖,这对单元测试来说非常困难。
我对单元测试和整体架构非常陌生,因此非常感谢任何建议。