Noksa / Allure.NUnit

C# NUnit Allure with improvements and SpecFlow3 adapter
MIT License
18 stars 6 forks source link

Delegate's stacktrace is lost by RunStep #46

Closed devAarno closed 4 years ago

devAarno commented 4 years ago

Describe the bug I have a convenient extension:

public static void Step(this string s, Action stepBody, params object[] stepParams) =>
    AllureLifecycle.Instance.RunStep(s, stepBody, stepParams);

It allows me to group a few steps by business logic, represent it as a hierarchical tree in allure reports and write high-order test scenario like:

"Open Preference Window".Step(() =>
{
    "Login".Step(() => { /* Do many staff */});
    ClickHere();
    ClickThenHere();
    ClickTheLastOne();
});

But I've found that if some exception appears in the Action (Delegate), allure shows a useless message like:

System.ArgumentException : ohohoh
Data:
  Rethrow: True

   at Allure.Commons.AllureLifecycle.StepRunner[TResult](String stepName, Delegate del, Boolean throwEx, Status stepStatusIfFailed, Object[] stepParams)
   at Allure.Commons.AllureLifecycle.RunStep(String stepName, Action stepBody, Object[] stepParams)
   at <...>.StringExtensions.Step(String s, Action stepBody, Object[] stepParams) in <...>\StringExtensions.cs:line 47
   at <...>.EmptyDataSource() in <...>\DataSourceTests.cs:line 188

So I can't understand what has happened in the Delegate.

To Reproduce Throw any unhandled exception inner the Action stepBody.

Expected behavior As I would like to know what has happened I have written my own dummy RunStep analog:

public static void Step(this string s, Action stepBody)
{
    var stepStatus = Status.passed;
    var throwedEx = (Exception) null;

    var str = $"{(object) Guid.NewGuid():N}";
    AllureLifecycle.Instance.StartStep(str, new StepResult
    {
        name = s, start = AllureLifecycle.ToUnixTimestamp(DateTimeOffset.Now)
    });

    try
    {
        stepBody();
    }
    catch (Exception ex)
    {
        throwedEx = ex;
        stepStatus = Status.failed;
    }
    finally
    {
        AllureLifecycle.Instance.UpdateStep(step => step.status = stepStatus);
        AllureLifecycle.Instance.StopStep(str);
    }

    if (null != throwedEx)
        ExceptionDispatchInfo.Capture(throwedEx).Throw();
}

All magic hidden in the ExceptionDispatchInfo.Capture(throwedEx).Throw();, so allure says:

System.ArgumentException : ohohoh

   at <...>.DataSourceCommon`1.SetTag(String tag) in <...>\DataSourceCommon.cs:line 31
   at <...>.DataSourceTests.<>c__DisplayClass2_1.<EmptyDataSource>b__0() in <...>\DataSource\DataSourceTests.cs:line 192
   at <...>.StringExtensions.Step(String s, Action stepBody) in <...>\StringExtensions.cs:line 31
--- End of stack trace from previous location where exception was thrown ---
   at <...>.StringExtensions.Step(String s, Action stepBody) in <...>\StringExtensions.cs:line 45
   at <...>.EmptyDataSource() in <...>\DataSourceTests.cs:line 188

As you can see the first block describes inner Action exception, the second is the rethrown exception by Step itself. It gives much more useful info.

So, what do you think about replacing

internal static TResult StepRunner<TResult>(string stepName, Delegate del, bool throwEx,
    Status stepStatusIfFailed,
    params object[] stepParams)
{
    var stepStatus = Status.passed;
    Exception throwedEx = null;
    /* <...> */
    finally
    {
        Instance.UpdateStep(step => step.status = stepStatus);
        Instance.StopStep(uuid);
    }

    if (throwEx && throwedEx != null) throw throwedEx;
    return resultFunc;
}

to

internal static TResult StepRunner<TResult>(string stepName, Delegate del, bool throwEx,
    Status stepStatusIfFailed,
    params object[] stepParams)
{
    var stepStatus = Status.passed;
    Exception throwedEx = null;
    /* <...> */
    finally
    {
        Instance.UpdateStep(step => step.status = stepStatus);
        Instance.StopStep(uuid);
    }

    if (throwEx && throwedEx != null) ExceptionDispatchInfo.Capture(throwedEx).Throw();
    return resultFunc;
}

? Have you any other suggestions?

Versions

Noksa commented 4 years ago

Hello! I think this is a great idea. I’ll update it soon.

Noksa commented 4 years ago

I also added a call to this method if an attribute AllureStep is used.

devAarno commented 4 years ago

Thank you!

Noksa commented 4 years ago

@devAarno try new beta version from nuget :)