最小起订量单元测试失败 - ASP.NET MVC
MOQ Unit Test Failing - ASP.NET MVC
有人可以帮忙解释一下为什么会失败吗?我想我可能会追踪到它与 User.Identity.Name 有关。它在 "Act" 处失败,我得到一个 System.NullReferenceException。然而,同一控制器中的另一种方法确实有效。
工作测试
[TestMethod]
public void Home_Index_Returns_ActionResult()
{
//Arrange
var mockRepository1 = new Mock<IEditDataRepository>();
var mockRepository2 = new Mock<IIdentityRepository>();
mockRepository1
.Setup(x => x.Edit(It.IsAny<UTCFormViewModel>(), It.IsAny<string>()));
HomeController controller = new HomeController(mockRepository1.Object, mockRepository2.Object);
//Act
ActionResult result = controller.Index();
//Assert
Assert.IsInstanceOfType(result, typeof(ActionResult));
}
测试无效(使用不同的方法)
[TestMethod]
public void Edit_Method_Test()
{
//Arrange
var mockRepository1 = new Mock<IEditDataRepository>();
var mockRepository2 = new Mock<IIdentityRepository>();
mockRepository1
.Setup(x => x.Edit(It.IsAny<UTCFormViewModel>(), It.IsAny<string>()));
HomeController controller = new HomeController(mockRepository1.Object, mockRepository2.Object);
//Act (Fails Here)
controller.Edit(It.IsAny<UTCFormViewModel>());
//Assert
mockRepository1.VerifyAll();
mockRepository2.VerifyAll();
}
控制器
namespace UTC.Controllers
{
[Authorize]
public class HomeController : Controller
{
private IEditDataRepository _editDataRepository;
private IIdentityRepository _identityRepository;
public HomeController(IEditDataRepository editDataRepository, IIdentityRepository identityRepository )
{
_editDataRepository = editDataRepository;
_identityRepository = identityRepository;
}
public ActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Field1, Field2")] UTCFormViewModel model)
{
if (ModelState.IsValid)
{
string fullWindowsUser = User.Identity.Name;
string windowsUser = _identityRepository.GetWindowsUser(fullWindowsUser);
_editDataRepository.Edit(model, windowsUser);
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
else
{
throw new HttpException(400, "ModelState Invalid");
}
}
}
}
存储库
namespace UTC.Repositories
{
public class IdentityRepository : IIdentityRepository
{
public string GetWindowsUser(string fullWindowsUser)
{
//Strip off the domain and lower text
var windowsUser = fullWindowsUser.ToString().ToLower().Split('\')[1];
return windowsUser;
}
}
}
存储库
namespace UTC.Repositories
{
public class EditDataRepository : IEditDataRepository
{
private UTCEntities db = new UTCEntities();
public void Edit(UTCFormViewModel model, string windowsUser)
{
db.ustp_UTCUpdate(windowsUser, model.Field1, model.Field2)
);
}
}
您正在访问 User.Identity.Name
但控制器的 User
属性 未在您的测试方法中设置,因此在访问时它将为空
您需要使用虚拟用户帐户设置控制器上下文。这是一个帮助程序 class,您可以使用它来模拟获取用户主体所需的 HttpContext
。
private class MockHttpContext : HttpContextBase {
private readonly IPrincipal user;
public MockHttpContext(string username, string[] roles = null) {
var identity = new GenericIdentity(username);
var principal = new GenericPrincipal(identity, roles ?? new string[] { });
user = principal;
}
public override IPrincipal User {
get {
return user;
}
set {
base.User = value;
}
}
}
在初始化目标控制器后的测试中,您需要设置控制器上下文
//...other code removed for brevity
var controller = new HomeController(mockRepository1.Object, mockRepository2.Object);
controller.ControllerContext = new ControllerContext {
Controller = controller,
HttpContext = new MockHttpContext("fakeuser@example.com")
};
//...other code removed for brevity
有人可以帮忙解释一下为什么会失败吗?我想我可能会追踪到它与 User.Identity.Name 有关。它在 "Act" 处失败,我得到一个 System.NullReferenceException。然而,同一控制器中的另一种方法确实有效。
工作测试
[TestMethod]
public void Home_Index_Returns_ActionResult()
{
//Arrange
var mockRepository1 = new Mock<IEditDataRepository>();
var mockRepository2 = new Mock<IIdentityRepository>();
mockRepository1
.Setup(x => x.Edit(It.IsAny<UTCFormViewModel>(), It.IsAny<string>()));
HomeController controller = new HomeController(mockRepository1.Object, mockRepository2.Object);
//Act
ActionResult result = controller.Index();
//Assert
Assert.IsInstanceOfType(result, typeof(ActionResult));
}
测试无效(使用不同的方法)
[TestMethod]
public void Edit_Method_Test()
{
//Arrange
var mockRepository1 = new Mock<IEditDataRepository>();
var mockRepository2 = new Mock<IIdentityRepository>();
mockRepository1
.Setup(x => x.Edit(It.IsAny<UTCFormViewModel>(), It.IsAny<string>()));
HomeController controller = new HomeController(mockRepository1.Object, mockRepository2.Object);
//Act (Fails Here)
controller.Edit(It.IsAny<UTCFormViewModel>());
//Assert
mockRepository1.VerifyAll();
mockRepository2.VerifyAll();
}
控制器
namespace UTC.Controllers
{
[Authorize]
public class HomeController : Controller
{
private IEditDataRepository _editDataRepository;
private IIdentityRepository _identityRepository;
public HomeController(IEditDataRepository editDataRepository, IIdentityRepository identityRepository )
{
_editDataRepository = editDataRepository;
_identityRepository = identityRepository;
}
public ActionResult Index()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Field1, Field2")] UTCFormViewModel model)
{
if (ModelState.IsValid)
{
string fullWindowsUser = User.Identity.Name;
string windowsUser = _identityRepository.GetWindowsUser(fullWindowsUser);
_editDataRepository.Edit(model, windowsUser);
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
else
{
throw new HttpException(400, "ModelState Invalid");
}
}
}
}
存储库
namespace UTC.Repositories
{
public class IdentityRepository : IIdentityRepository
{
public string GetWindowsUser(string fullWindowsUser)
{
//Strip off the domain and lower text
var windowsUser = fullWindowsUser.ToString().ToLower().Split('\')[1];
return windowsUser;
}
}
}
存储库
namespace UTC.Repositories
{
public class EditDataRepository : IEditDataRepository
{
private UTCEntities db = new UTCEntities();
public void Edit(UTCFormViewModel model, string windowsUser)
{
db.ustp_UTCUpdate(windowsUser, model.Field1, model.Field2)
);
}
}
您正在访问 User.Identity.Name
但控制器的 User
属性 未在您的测试方法中设置,因此在访问时它将为空
您需要使用虚拟用户帐户设置控制器上下文。这是一个帮助程序 class,您可以使用它来模拟获取用户主体所需的 HttpContext
。
private class MockHttpContext : HttpContextBase {
private readonly IPrincipal user;
public MockHttpContext(string username, string[] roles = null) {
var identity = new GenericIdentity(username);
var principal = new GenericPrincipal(identity, roles ?? new string[] { });
user = principal;
}
public override IPrincipal User {
get {
return user;
}
set {
base.User = value;
}
}
}
在初始化目标控制器后的测试中,您需要设置控制器上下文
//...other code removed for brevity
var controller = new HomeController(mockRepository1.Object, mockRepository2.Object);
controller.ControllerContext = new ControllerContext {
Controller = controller,
HttpContext = new MockHttpContext("fakeuser@example.com")
};
//...other code removed for brevity