I have very simple ASP.NET Core project. This is my controller:
public class AdminController : Controller
{
private readonly IProductRepository _repository;
public AdminController(IProductRepository repository)
{
_repository = repository;
}
public ViewResult Index()
{
return View(_repository.Products.OrderBy(p => p.Id));
}
public ViewResult Edit(int id)
{
Product product = _repository.Products.FirstOrDefault(p => p.Id == id);
return View(product);
}
[HttpPost]
public ActionResult Edit(Product product)
{
if (ModelState.IsValid)
{
_repository.SaveProduct(product);
TempData["message"] = $"{product.Name} has been saved";
return RedirectToAction("Index");
}
return View(product);
}
}
And my view _AdminLayout.cshtml
<main role="main" class="pb-3">
<div>
@if (TempData["message"] != null)
{
<div class="alert alert-success">
@TempData["message"]
</div>
}
</div>
@RenderBody()
</main>
And finally Index.cshtml
view
@model System.Collections.Generic.IEnumerable<Domains.Entities.Product>
@{
ViewBag.Title = "Admin";
Layout = "_AdminLayout";
}
<div>
// some cshtml code ...
</div>
As you can see, I am waiting the following business logic:
Save a product;
Redirect to Index.cs
admin view
I see message about successfully saved product on the top of my screen.
But nothing happened. I don't see the message after saving and TempData
is null after redirect to Index
.
And, additionally, I have a problem with unit test of this method.
Here is my test code:
[Test]
public void Can_Save_Valid_Changes()
{
Mock<IProductRepository> mock = new Mock<IProductRepository>();
AdminController controller = new AdminController(mock.Object);
Product product = new Product { Name = "Test"};
IActionResult result = controller.Edit(product);
// check if have saved product to repo
mock.Verify(m => m.SaveProduct(product));
Assert.IsNotInstanceOf<ViewResult>(result);
}
I use NUnit
library for testing. After running the test I have the following message from test: object reference not set to an instance of an object
. It seems putting value to TempData
throws this exception during the test.
Tell me please, what is happening with this TempData
? Where is the mistake? I had seen a lot of questions about strange behavior of TempData
and I did not found an answer for me. I appreciate any help.
When unit testing a controller that accesses TempData
you need to create a TempDataDictionary
for the controller
[Test]
public void Can_Save_Valid_Changes() {
//Arrange
var httpContext = new DefaultHttpContext();
var tempData = new TempDataDictionary(httpContext, Mock.Of<ITempDataProvider>());
var mock = new Mock<IProductRepository>();
AdminController controller = new AdminController(mock.Object);
controller.TempData = tempData;
Product product = new Product { Name = "Test"};
//Act
IActionResult result = controller.Edit(product);
//Assert
// check if have saved product to repo
mock.Verify(m => m.SaveProduct(product));
Assert.IsNotInstanceOf<ViewResult>(result);
Assert.IsTrue(tempData.ContainsKey("message"));
}