gpt4 book ai didi

c# - 为 ASP .NET MVC 创建单元测试时出现的问题

转载 作者:行者123 更新时间:2023-12-02 09:23:34 24 4
gpt4 key购买 nike

我正在为 ASP .NET MVC Controller 类创建一些单元测试,但遇到了一些非常奇怪的错误:

我的 Controller 代码如下:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(JournalViewModel journal)
{
var selectedJournal = Mapper.Map<JournalViewModel, Journal>(journal);

var opStatus = _journalRepository.DeleteJournal(selectedJournal);
if (!opStatus.Status)
throw new System.Web.Http.HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));

return RedirectToAction("Index");
}

我的测试代码如下:

[TestMethod]
public void Delete_Journal()
{
// Arrange

// Simulate PDF file
HttpPostedFileBase mockFile = Mock.Create<HttpPostedFileBase>();
Mock.Arrange(() => mockFile.FileName).Returns("Test.pdf");
Mock.Arrange(() => mockFile.ContentLength).Returns(255);

// Create view model to send.
JournalViewModel journalViewModel = new JournalViewModel();
journalViewModel.Id = 1;
journalViewModel.Title = "Test";
journalViewModel.Description = "TestDesc";
journalViewModel.FileName = "TestFilename.pdf";
journalViewModel.UserId = 1;
journalViewModel.File = mockFile; // Add simulated file

Mock.Arrange(() => journalRepository.DeleteJournal(null)).Returns(new OperationStatus
{
Status = true
});

// Act
PublisherController controller = new PublisherController(journalRepository, membershipRepository);
RedirectToRouteResult result = controller.Delete(journalViewModel) as RedirectToRouteResult;

// Assert
Assert.AreEqual(result.RouteValues["Action"], "Index");
}

问题 1 - 映射异常:

每次运行测试时,我都会收到以下异常:

Test Name: Delete_Journal Test
FullName: Journals.Web.Tests.Controllers.PublisherControllerTest.Delete_Journal
Test Source: \Source\Journals.Web.Tests\Controllers\PublisherControllerTest.cs : line 132
Test Outcome: Failed Test Duration: 0:00:00,3822468

Result StackTrace: at Journals.Web.Controllers.PublisherController.Delete(JournalViewModel journal) in \Source\Journals.Web\Controllers\PublisherController.cs:line 81 at Journals.Web.Tests.Controllers.PublisherControllerTest.Delete_Journal() in \Source\Journals.Web.Tests\Controllers\PublisherControllerTest.cs:line 156 Result Message: Test method Journals.Web.Tests.Controllers.PublisherControllerTest.Delete_Journal threw exception: AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.

Mapping types: JournalViewModel -> Journal Journals.Model.JournalViewModel -> Journals.Model.Journal

Destination path: Journal

Source value: Journals.Model.JournalViewModel

类之间似乎存在映射问题JournalViewModelJournal ,但我不知道那是哪里。我将此代码添加到 Application_StartGlobal.asax.cs :

Mapper.CreateMap<Journal, JournalViewModel>();
Mapper.CreateMap<JournalViewModel, Journal>();

映射自JournalJournalViewModel正在工作。

最后我尝试添加 Mapper.CreateMap<JournalViewModel, Journal>();作为 Delete 的第一行方法,然后一切正常,但我不知道为什么。

问题 2 - HTML 异常

使用上述解决方法运行映射后,我遇到一个问题,其中属性 Status来自var opStatus = _journalRepository.DeleteJournal(selectedJournal);始终为假,即使我使用 Mock 来覆盖它并使其始终为真。这会导致抛出不应该发生的 HTML 异常。

编辑

我将 Application_Start 更改为:

Mapper.Initialize(cfg =>
{
cfg.CreateMap<Journal, JournalViewModel>();
cfg.CreateMap<JournalViewModel, Journal>();
});

但我仍然有同样的错误。

编辑 - 问题 2 已解决

事实证明,我忘记将映射添加到我的单元测试类中,因此我执行了以下操作:

[TestInitialize]
public void TestSetup()
{
// Create necessary mappings
Mapper.CreateMap<Journal, JournalViewModel>();
Mapper.CreateMap<JournalViewModel, Journal>();

//...other code omitted for brevity
}

事实证明,这就是问题的根源。我认为由于 Global.asax.cs Application_Start() 在单元测试中从未被调用,因此映射从未被创建,因此我必须在单元测试初始化​​中自己执行此操作。

最佳答案

问题1

Automapper 具有 Static and Instance API 。您应该考虑将实例 API 与 IMapper 一起使用,并将其注入(inject)到您的 Controller 中。

public class PublisherController : Controller {
private readonly IMapper mapper;

public PublisherController(IJournalRepository journalRepository, IMembershipRepositry membershipRepository, IMapper mapper) {
//...other code omitted for brevity
this.mapper = mapper;
}

//...other code omitted for brevity

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(JournalViewModel journal) {
var selectedJournal = mapper.Map<JournalViewModel, Journal>(journal);

var opStatus = _journalRepository.DeleteJournal(selectedJournal);
if (!opStatus.Status)
throw new System.Web.Http.HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));

return RedirectToAction("Index");
}
}

这将允许根据需要更好地模拟/伪造/配置映射。您应该确保配置 IMapper 以将依赖项注入(inject)到您的 Controller 中。

如果您无法更改实例 api,那么您需要确保映射器在运行测试之前已初始化

Mapper.Initialize(cfg => {
cgf.CreateMap<JournalViewModel, Journal>();
});

问题2

你的测试安排是

Mock.Arrange(() => journalRepository.DeleteJournal(null)).Returns(new OperationStatus
{
Status = true
});

您意识到,这对于使用实际实例调用 journalRepository.DeleteJournal 的情况不起作用。假设您正在使用 Telerik 的 JustMock,您应该安排一个更灵活的参数。

Mock.Arrange(() => journalRepository.DeleteJournal(Arg.IsAny<Journal>())).Returns(new OperationStatus
{
Status = true
});

来源:Handling Arguments in JustMock Arrangements

完成测试:实例 API

[TestMethod]
public void Delete_Journal() {
// Arrange

//Configure mapping just for this test but something like this
//should be in accessible from your composition root and called here.
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Journal, JournalViewModel>();
cfg.CreateMap<JournalViewModel, Journal>();
});

var mapper = config.CreateMapper(); // IMapper

// Simulate PDF file
var mockFile = Mock.Create<HttpPostedFileBase>();
Mock.Arrange(() => mockFile.FileName).Returns("Test.pdf");
Mock.Arrange(() => mockFile.ContentLength).Returns(255);

// Create view model to send.
var journalViewModel = new JournalViewModel();
journalViewModel.Id = 1;
journalViewModel.Title = "Test";
journalViewModel.Description = "TestDesc";
journalViewModel.FileName = "TestFilename.pdf";
journalViewModel.UserId = 1;
journalViewModel.File = mockFile; // Add simulated file

var status = new OperationStatus {
Status = true
};

Mock.Arrange(() => journalRepository.DeleteJournal(Arg.IsAny<Journal>())).Returns(status);

var controller = new PublisherController(journalRepository, membershipRepository, mapper);

// Act
var result = controller.Delete(journalViewModel) as RedirectToRouteResult;

// Assert
Assert.AreEqual(result.RouteValues["Action"], "Index");
}

完整测试:静态 API

[TestMethod]
public void Delete_Journal() {
// Arrange

//Configure mapping just for this test but something like this
//should be in accessible from your composition root and called here.
Mapper.Initialize(cfg => {
cfg.CreateMap<Journal, JournalViewModel>();
cfg.CreateMap<JournalViewModel, Journal>();
});

// Simulate PDF file
var mockFile = Mock.Create<HttpPostedFileBase>();
Mock.Arrange(() => mockFile.FileName).Returns("Test.pdf");
Mock.Arrange(() => mockFile.ContentLength).Returns(255);

// Create view model to send.
var journalViewModel = new JournalViewModel();
journalViewModel.Id = 1;
journalViewModel.Title = "Test";
journalViewModel.Description = "TestDesc";
journalViewModel.FileName = "TestFilename.pdf";
journalViewModel.UserId = 1;
journalViewModel.File = mockFile; // Add simulated file

var status = new OperationStatus {
Status = true
};

Mock.Arrange(() => journalRepository.DeleteJournal(Arg.IsAny<Journal>())).Returns(status);

var controller = new PublisherController(journalRepository, membershipRepository);

// Act
var result = controller.Delete(journalViewModel) as RedirectToRouteResult;

// Assert
Assert.AreEqual(result.RouteValues["Action"], "Index");
}

关于c# - 为 ASP .NET MVC 创建单元测试时出现的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39864288/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com