【问题标题】:Moq, TDD and multiple layersMoq、TDD 和多层
【发布时间】:2012-05-14 02:27:57
【问题描述】:

我有一个定义我的存储库的数据程序集。

然后我有一个定义我的服务的服务程序集,每个服务都有一个由 Ninject 注入到构造函数中的存储库。

当我对我的服务方法进行单元测试时,一切都很好:

[TestClass]
public class UserTests
{
    IQueryable<User> users;
    int userID;

    public UserTests()
    {
        users = new List<User>()
        {
            new User { EmailAddress = "known@user.com", Password = "password", ID = 1}
        }.AsQueryable();
    }

    [TestMethod]
    public void Known_User_Can_Login()
    {
        // Arrange
        var repository = new Mock<IUserRepository>();
        var service = new UserService(repository.Object);

        repository.Setup(r => r.GetAll())
           .Returns(users);

        // Act
        bool loggedIn = service.UserLogin("known@user.com", "password", out userID);

        // Assert
        Assert.IsTrue(loggedIn);
        Assert.AreEqual(1, userID);
    }

    [TestMethod]
    public void Unknown_User_Cannot_Login()
    {
        // Arrange
        var repository = new Mock<IUserRepository>();
        var service = new UserService(repository.Object);

        repository.Setup(r => r.GetAll())
            .Returns(users);

        // Act
        bool loggedIn = service.UserLogin("unknown@user.com", "password", out userID);

        //
        Assert.IsFalse(loggedIn);
    }
}

但是,我在测试我的控制器时遇到了问题(下一级)。

我的控制器依赖于服务,而服务依赖于存储库。我似乎无法让我的控制器测试正常工作。这是我目前所拥有的:

 [TestClass]
public class AccountTests
{
    IQueryable<User> users;

    public AccountTests()
    {
        users = new List<User>()
        {
            new User { CompanyId = 1, EmailAddress =  "known@user.com", Password = "password"},
            new User { CompanyId = 1, EmailAddress = "unknown@user.com", Password = "password"}
        }.AsQueryable();
    }

    [TestMethod]
    public void Known_User_Can_Login()
    {
        int userID = 0;

        var repo = new Mock<IUserRepository>();

        // Arrange
        var service = new Mock<UserService>(repo.Object);
        var controller = new AccountController(service.Object);

        // Act
        var result = controller.Login(new LoginModel { EmailAddress = "known@user.com", Password = "password" }) as RedirectToRouteResult;

        // Assert
        service.Verify(x => x.UserLogin("known@user.com", "password", out userID), Times.Once());
        Assert.AreEqual("Index", result.RouteValues["Action"]);
    }
}

我不断收到关于实例化 UserService 的错误(我正在尝试将 UserRepository 的实例传递给它,但它不起作用)。

我一定是在做一些愚蠢的事情,但是什么?

【问题讨论】:

  • 我不知道最小起订量/ninject,但这是我的看法:因为你在模拟你的服务,所以它永远不需要存储库。你真正的实现可能。您只需要向下测试一个级别。你有你的 SUT,只需要模拟 SUT 将要访问的对象。
  • @Paul 我有兴趣查看您用于应用的组合根目录。

标签: asp.net-mvc-3 tdd ninject moq


【解决方案1】:

确保 UserService 是一个接口。

此外,您必须在您的第二个测试中创建 IUserRepository 的实例,就像您在此处所做的那样:

var repo = new Mock<IUserRepository>();
// Arrange
var service = new Mock<UserService>(repo.Object);

由于 UserService 是模拟的,它无论如何都不会调用 IUserRepository 并且您不必在创建模拟时提供它的依赖项。

您需要做的只是以这种方式为 UserService 创建模拟:

var service = new Mock<UserService>();

即使是严格的 UserService 通常也依赖于存储库,Moq 只会提供对方法的预设响应,因此不需要调用实际的存储库。

【讨论】:

    【解决方案2】:

    UserService 类我猜不是接口或抽象类,如果不是那么它必然会失败,因为 Mock 无法创建UserService 的实现。因此,要么为 UserService 创建一个接口,要么将其定义为抽象类,或将其实例化,如下所示:

    var service = new UserService(repo.Object);

    或者您可以使用 Mock.Create&lt;UserService&gt;(),但您需要使用 Mock.Provide&lt;T&gt;() api 提供 UserService 所需的所有实现。

    希望这会有所帮助。

    如果这不是问题,请使用 UserService 和您的存储库的类更新问题

    【讨论】:

      猜你喜欢
      • 2011-08-07
      • 1970-01-01
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-24
      • 2014-08-20
      • 2019-04-25
      相关资源
      最近更新 更多