用微软的假货来嘲弄

本文关键字:嘲弄 微软的 | 更新日期: 2023-09-27 18:19:22

我用async(.net 4.5)方法密封了类,这些方法需要被模拟。我用的是微软的假货,所以它们是"垫片"。下面的代码是我需要做的一个例子。它构建,但当运行时,"Login"控制器方法中的"LoginAsync"方法被调用,测试挂起。

  [TestMethod]
  public async Task LoginPost_Returns() {
     using (ShimsContext.Create()) {
        var c = new TestController();
        var user=new User();
        Fakes.ShimUserManager.AllInstances.LoginAsyncString = (um, u) => new Task<IUser>(() => { return user; });
        //call controller method  
        var result = await c.Login(model, returnUrl) as ViewResult;
        var expectedViewName = "Index";
        Assert.IsNotNull(result);
        Assert.AreEqual(expectedViewName, result.ViewName);
     }
//Controller method
public async Task<ActionResult> Login(LoginModel model, string returnUrl) {
     var user = await UserManager.LoginAsync(model.UserName, model.password);
     return View();
}

用微软的假货来嘲弄

不要在async代码中使用Task构造函数。如果您只需要一个完整的带有返回值的Task,请使用Task.FromResult:

IUser user = new User();
Fakes.ShimUserManager.AllInstances.LoginAsyncString = (um, u) => Task.FromResult(user);

作为一个额外的提示,在单元测试中覆盖这些情况是一个好主意:

  • 同步成功(Task.FromResult(user)).
  • 异步成功(Task.Run(() => user)).
  • 异步错误(Task.Run(() => { throw new InvalidOperationException("or whatever"); return user; })).
Fakes.ShimUserManager.AllInstances.LoginAsyncString =
    (um, u) => new Task<IUser>(() => { return user; });

创建一个未启动的Task。您的代码挂起,因为Task从未启动。要解决这个问题,可以:

  1. 使用Task.Run()(或Task.Factory.StartNew()),返回已经启动的Task
  2. 使用Task.FromResult()。返回一个已经完成的Task .
  3. 使lambda async:

    Fakes.ShimUserManager.AllInstances.LoginAsyncString = async (um, u) => user;