3

我使用需要模拟的 async(.net 4.5) 方法密封了类。我正在使用 Microsoft Fakes,因此它们将是“垫片”。下面的代码是我需要做的一个例子。它会构建,但是当运行并调用“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();
}
4

2 回答 2

9

不要在代码中使用Task构造函数。async如果您只需要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; }))。
于 2013-06-21T00:23:00.813 回答
3
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;
    
于 2013-06-21T00:21:58.813 回答