【问题标题】:Throwing FormCancelledException from await instead of AggregateException in unit test在单元测试中从等待而不是 AggregateException 抛出 FormCancelledException
【发布时间】:2018-06-13 16:50:14
【问题描述】:

我目前正在尝试在使用 Microsoft Bot Framework 的应用程序中测试以下代码。

public async Task ResumeAfterCalculation_v2FormDialog(IDialogContext context, IAwaitable<Calculation_v2Form> result)
{
    try
    {
        var extractedCalculationForm = await result;
        //Removed additional code
    }
    catch (FormCanceledException ex)
    {
        var reply = "You have canceled the operation.";
        await _chat.PostAsync(context, reply);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
    finally
    {
        context.Done<object>(null);
    }
}

当用户向机器人键入“退出”时,“等待结果”代码会引发 FormCanceledException,并且代码会退出表单。

在创建测试时,我实现了一个类来模拟 IAwaitable:

public class TaskAwaiterHelper<T> : IAwaiter<T>, IAwaitable<T>
{
    public Task<T> Task { get; }

    public TaskAwaiterHelper(T obj)
    {
        this.Task = System.Threading.Tasks.Task.FromResult(obj);
    }

    public TaskAwaiterHelper(Task<T> task)
    {
        this.Task = task;
    }

    public bool IsCompleted { get { return Task.IsCompleted; } }

    public void OnCompleted(Action action)
    {
        SynchronizationContext context = SynchronizationContext.Current;
        TaskScheduler scheduler = context == null ? TaskScheduler.Current
            : TaskScheduler.FromCurrentSynchronizationContext();
        Task.ContinueWith(ignored => action(), scheduler);
    }

    public T GetResult()
    {
        return Task.Result;
    }

    public IAwaiter<T> GetAwaiter()
    {
        return this;
    }
}

然后我创建了以下测试:

[Fact]
public async Task ResumeAfterCalculation_v2FormDialog_WasCancelled_ThenCallsDone()
{
    //Arrange
    var chat = new Mock<IChatHelper>();
    var calculationApi = new Mock<ICalculationApi>();
    var dialogContextMock = new Mock<IDialogContext>();
    var rootLuisDialog = new RootLuisDialog(chat.Object, calculationApi.Object);

    var taskAwaiter = new TaskAwaiterHelper<Calculation_v2Form>(new Task<Calculation_v2Form>(() =>
    {
        throw new FormCanceledException("Error created for test test", null);
    }));

    taskAwaiter.Task.Start();

    //Act
    await rootLuisDialog.ResumeAfterCalculation_v2FormDialog(dialogContextMock.Object, taskAwaiter);

    //Assert
    chat.Verify(c => c.PostAsync(dialogContextMock.Object, "You have canceled the operation."), Times.Once());

    dialogContextMock.Verify(t => t.Done<object>(null), Times.Once());
}

现在无论我尝试做什么,在 IAwaitable 中引发的异常都被包装在 AggregateException 中,因此我们总是以 catch (Exception ex) 而不是所需的 catch (FormCanceledException ex) 结束

有没有办法让任务抛出特定异常而不是 AggregateException(我的意思是应该有,因为机器人框架本身似乎能够做到这一点)。

【问题讨论】:

    标签: c# unit-testing botframework


    【解决方案1】:

    刚刚找到答案,我基本上新建了一个类:

    public class ExceptionThrower : IAwaitable<Calculation_v2Form>
    {
        public IAwaiter<Calculation_v2Form> GetAwaiter()
        {
            throw new FormCanceledException("Error created for test test", null);
        }
    }
    

    并且刚刚将这个提供给方法:

    var exceptionThrower = new ExceptionThrower();
    
    await rootLuisDialog.ResumeAfterCalculation_v2FormDialog(dialogContextMock.Object, exceptionThrower);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-14
      • 2013-08-21
      • 2016-03-20
      • 1970-01-01
      • 1970-01-01
      • 2019-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多