【问题标题】:ReturnsAsync in Moq is not working起订量中的 ReturnsAsync 不起作用
【发布时间】:2016-04-21 10:07:30
【问题描述】:

这是我的代码

public interface IUserManager
{
  Task<int> PostUser(User user);
  IQueryable<User> GetUserById(long userId);
}

public class UserManager : IUserManager 
{
    public UserManager(DataContext context)
    {
        this.DataContext = context;
    }
    public async Task<int> PostUser(User user)
    {
        this.DataContext.User.Add(user);
        return await this.DataContext.SaveChangesAsync().ConfigureAwait(false);
    }

   public IQueryable<User> GetUserById(long userId)
   {
      return this.DataContext.User
        .Where(userNotes => userNotes.UserId == userId).AsQueryable();
   }
}

控制器:

public class UserController : BaseController
{
    private readonly IUserManager userManager;

    public UserController()
    {
        this.userManager = new UserManager();
    }

    public UserController(IUserManager userManager)
    {
        this.userManager = userManager;
    }

    [EnableQuery]
    public IQueryable<User> Get([FromODataUri]long userId)
    {
        return this.userManager.GetUserById(userId);
    }

    public HttpResponseMessage Post(User user)
    {
        if (userNote == null || !ModelState.IsValid)
        {
            return this.BuildErrorResponse(ResponseCodes.INVALID_MISSING_INPUTS);
        }

        if (this.userManager.PostUser(user).Result <= 0)
        {
            return this.BuildErrorResponse(ResponseCodes.USER_ADD_FAILED);
        }

        return this.BuildSuccessResponse<User>(ResponseCodes.USER_ADDED, user);
    }
}

起订量测试:

[TestClass]
public class UnitTest
{
    IUserManager userManagerMock;
    Mock<IUserManager> iUserManagerMock;

    [TestInitialize]
    public void Setup()
    {
        //.. setup variables and mock data
        userManagerMock = new UserManager(ContextMock.Object);
        iUserManagerMock.Setup(u => u.PostUser(It.IsAny<User>()))
                .ReturnsAsync(1);
    }

    [TestMethod]
    public void Post()
    {
        var controller = new UserController(userManagerMock); //userNotesManagerMock will have the mock data                                           //and mock methods setup
            var httpResponse = controller.Post(userPostMock); //userPostMock will have mock data to save

            //Assert.AreEqual(HttpResponseMessage, result);
    }
}

我写了一个 post 方法,就像你在这里看到的那样。我也有一个 Get 方法,它可以完美地处理模拟数据。

但是当我通过 Post 进行调试时,以下语句的数据总是返回零而不是 1,这是我在 ReturnsAsync 中设置的。

this.userManager.PostUser(user).Result <= 0 //this always gives me zero

帖子有什么问题?我做错了什么吗?

谁能解释一下这个


编辑

这是测试方法和设置的 GET 版本

[TestInitialize]
public void Setup()
{
    //dummy data setup
    UserMock = new List<User>
    {
        new User { //blah blah properties }
    }.AsQueryable();

    //context setup
    dbSetUserMock = new Mock<IDbSet<User>>();
    dbSetUserMock.Setup(m => m.Provider).Returns(UserMock.Provider);
    dbSetUserMock.Setup(m => m.Expression).Returns(UserMock.Expression);
    dbSetUserMock.Setup(m => m.ElementType).Returns(UserMock.ElementType);
    dbSetUserMock.Setup(m => m.GetEnumerator()).Returns(UserMock.GetEnumerator());

    UserContextMock = new Mock<DataContext>();
    UserContextMock.Setup(s => s.User).Returns(dbSetUserMock.Object);

    //inject the context to manager
    UserManagerMock = new UserManager(UserContextMock.Object);

    iUserManagerMock = new Mock<IUserManager>();
    iUserManagerMock.Setup(notes => notes.PostUserNote(It.IsAny<User>()))
        .ReturnsAsync(1);
}

[TestMethod]
public void Get_User_Success()
{
    var controller = new UserController(UserManagerMock);
    var values = controller.Get(100);

    Assert.AreEqual(100, values.FirstOrDefault().UserId);
}

Get_User_Success 现在可以很好地与虚拟数据集配合使用,并且我能够在没有iUserManagerMock 对象的情况下通过测试。原因是我想在 Manager 类中执行 GetUser() 方法内的代码。

我还有一个问题。作为 ,我在 ReturnAsync for Post 操作中将预期结果设置为 1。如何为失败案例构建测试方法,因为 POST 方法的返回对于失败案例仍然为 1?

【问题讨论】:

    标签: asp.net-mvc asp.net-web-api asp.net-web-api2 moq


    【解决方案1】:

    您正在混淆设置。如果被测方法是UserController.Post,并且你想通过IUserManager接口模拟UserManager,那么你不需要手动新建一个。

    [TestClass]
    public class UnitTest {
    
        [TestMethod]
        public void UserController_Should_Post_User_Ok() {
            //Arrange
            var userPostMock = new User { UserId = 100 };
            var userManagerMock = new Mock<IUserManager>();
            userManagerMock.Setup(u => u.PostUser(It.IsAny<User>())).ReturnsAsync(1);
            var controller = new UserController(userManagerMock.Object);
            controller.Request = new HttpRequestMessage();
            controller.Configuration = new HttpConfiguration();
    
            //Act
            var httpResponse = controller.Post(userPostMock);
    
            //Assert
            Assert.AreEqual(System.Net.HttpStatusCode.OK, httpResponse.StatusCode);
        }
    
        [TestMethod]
        public void UserController_Should_Post_User_Fail() {
            //Arrange
            var userPostMock = new User { UserId = 100 };
            var userManagerMock = new Mock<IUserManager>();
            userManagerMock.Setup(u => u.PostUser(It.IsAny<User>())).ReturnsAsync(0);//Replicating a failed post
            var controller = new UserController(userManagerMock.Object);
            controller.Request = new HttpRequestMessage();
            controller.Configuration = new HttpConfiguration();
    
            //Act
            var httpResponse = controller.Post(userPostMock);
    
            //Assert
            Assert.AreEqual(System.Net.HttpStatusCode.InternalServerError, httpResponse.StatusCode);
        }
    
        [TestMethod]
        public void UserManager_Should_Get_User_Success() {
            //Arrange
            var userMock = new List<User>
            {
                new User (){ UserId=100 }
            }.AsQueryable();
    
            //context setup
            var dbSetUserMock = new Mock<IDbSet<User>>();
            dbSetUserMock.Setup(m => m.Provider).Returns(userMock.Provider);
            dbSetUserMock.Setup(m => m.Expression).Returns(userMock.Expression);
            dbSetUserMock.Setup(m => m.ElementType).Returns(userMock.ElementType);
            dbSetUserMock.Setup(m => m.GetEnumerator()).Returns(userMock.GetEnumerator());
    
            var userContextMock = new Mock<DataContext>();
            userContextMock.Setup(s => s.User).Returns(dbSetUserMock.Object);
            //inject the context to manager
            var userManagerMock = new UserManager(userContextMock.Object);
    
            //Act
            var values = userManagerMock.GetUserById(100);
    
            //Assert
            Assert.AreEqual(100, values.FirstOrDefault().UserId);
        }
    }
    

    【讨论】:

    • 我使用userManagerMock 调用GETiUserManagerMock 调用POST。如果我使用您提出的模拟对象模拟 Get 请求,则测试将不会执行管理器类中 GET 方法内部的逻辑
    • 那么您需要显示更多代码,因为答案是基于您原始帖子中针对特定问题的代码。我相信 Get 的问题也将与您如何设置模拟直接相关。单元测试也应该是单独进行的。如果您在测试之间共享模拟,您将遇到那个确切的问题
    • @KarthikChintala 显示 Get 测试以更好地理解问题。
    • 好吧,你混淆了你真正想要测试的东西。如果UserManager 是被测系统,那么测试应该集中在那个系统上
    • GetUser 更新IUserManeger 并且您的原始帖子也排除了该类的构造函数。仅凭零碎的信息很难提供帮助。
    猜你喜欢
    • 2015-10-29
    • 2015-10-10
    • 2015-02-02
    • 1970-01-01
    • 2020-12-06
    • 1970-01-01
    • 2014-01-03
    • 2016-08-24
    • 1970-01-01
    相关资源
    最近更新 更多