在单元测试

时间:2018-06-13 16:50:15

标签: c# unit-testing botframework

我目前正在尝试在使用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);
    }
}

当用户向机器人输入'quit'时,'await result'代码抛出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)

中结束

有没有办法让Task抛出一个特定的Exception而不是AggregateException(我的意思是应该有,因为bot框架本身似乎能够做到这一点)。

1 个答案:

答案 0 :(得分: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);