【发布时间】:2012-02-01 13:50:24
【问题描述】:
我有一个单元测试来检查我的 AccountController.LogIn 方法。返回重定向结果表示成功,否则返回查看结果。
测试总是失败,因为返回类型总是 viewresult,即使测试应该返回成功,因为凭据是有效的,但是我无法确定问题出在哪里。 我的测试方法: CustomerRepositoryTest.cs
[TestMethod]
public void Can_Login_With_Valid_Credentials()
{
// Arrange
Mock<IAddressRepository> mockAddressRepository = new Mock<IAddressRepository>();
Mock<ICustomerRepository> mockCustomerRepository = new Mock<ICustomerRepository>();
Mock<IOrderRepository> mockOrderRepository = new Mock<IOrderRepository>();
LoginViewModel model = new LoginViewModel
{
Email = "me@5.com",
Password = "password"
};
AccountController target = new AccountController(mockCustomerRepository.Object, mockAddressRepository.Object, mockOrderRepository.Object);
// Act
ActionResult result = target.LogIn(model);
// Assert
Assert.IsInstanceOfType(result, typeof(RedirectResult));
Assert.AreEqual("", ((RedirectResult)result).Url);
}
当我运行测试时,当我调用 ValidateUser 时,它在 My AccountController 登录方法中失败 AccountController.cs
if (Membership.ValidateUser(LoginModel.Email, LoginModel.Password))
{
...
return RedirectToRoute(new
{
controller = "Account",
action = "Details"
});
}
else
{
return View();
}
我的自定义 MembershipProvider ValidateUser 如下所示:
AccountMembershipProvider.cs
public class AccountMembershipProvider : MembershipProvider
{
[Inject]
public ICustomerRepository repository { get; set; }
public override bool ValidateUser(string username, string password)
{
var cust = repository.GetAllCustomers().SingleOrDefault..
当我正常运行应用程序(即不测试)时,登录工作正常。在应用程序中,我将 CustomerRepository 注入到 Global.asax 中的自定义成员资格提供程序中:
public class MvcApplication : System.Web.HttpApplication
{
private IKernel _kernel = new StandardKernel(new MyNinjectModules());
internal class MyNinjectModules : NinjectModule
{
public override void Load()
{
Bind<ICustomerRepository>().To<CustomerRepository>();
}
}
protected void Application_Start()
{
_kernel.Inject(Membership.Provider);
...
是否在单元测试时不运行 Global.asax 代码?所以我的自定义提供程序没有被注入,因此失败了?
更新 我模拟了我的 Provider 类并将模拟的 CustomerRepository 对象传递给它。
Mock<AccountMembershipProvider> provider = new Mock<AccountMembershipProvider>();
provider.Object.repository = mockCustomerRepository.Object;
然后我为我要测试的方法创建了一个设置:
mockCustomerRepository.Setup(m => m.IsValidLogin("me@5.com", "password")).Returns(true);
但不幸的是,我每次仍然失败。回答关于我是否需要一个真实的或模拟的对象进行测试的问题 - 我并不挑剔,我只是想让它在此刻工作!
更新 2
我进行了这些更改,虽然它仍然失败,但它让我能够确定具体问题。在调试测试时,我发现当我调用覆盖时
Membership.ValidateUser(LoginModel.Email, LoginModel.Password)
Membership.Provider 是 SqlMembershipProvider 类型(可能是默认类型),因此验证失败。
如果我将提供程序转换为我的自定义提供程序...
((AccountMembershipProvider)Membership.Provider).ValidateUser(LoginModel.Email, LoginModel.Password)
我在运行测试时收到 InvalidCastException。因此,我模拟的 AccountMembershipProvider 似乎没有用于测试,而是使用了默认提供程序。
我想你已经在评论中指出了这一点:
// set your mock provider in your AccountController
但是我不确定您的确切意思 - 我的 AccountController 上没有属性可将提供程序分配给,而且我没有将其注入到构造函数中。
【问题讨论】:
-
只是为了让您知道,我在当天早些时候的回答中添加了更多信息并进行了编辑。不要犹豫,要求澄清或更具体的信息。
-
@Gilles - 我实施了你的建议(见更新)。他们为我澄清了很多,尽管不幸的是每次都失败了!我需要为 Provider 和 Repository 类定义设置方法吗?
-
我用一个例子更新了我的帖子。基本上,如果您的提供程序被模拟,则无需为其依赖项创建模拟,因为模拟对象不会调用它们。
-
@Gilles - 查看更新。测试仍然使用默认提供程序而不是我的自定义提供程序。非常感谢您在这方面的帮助,谢谢。
-
在 Membership.ValidateUser 中,ValidateUser 是静态方法吗?
标签: asp.net-mvc-3 unit-testing ninject moq