c# - 如何使用应有的自定义断言并维护特定于调用站点的断言消息?

标签 c# unit-testing assert xunit shouldly

我正在使用 the excellent Shouldly library在我的 xUnit 测试中,我发现自己在不同的测试中使用了断言的集合序列,所以我将它们组合成新的断言扩展方法 - 但是当我这样做时,我丢失了 Shouldly的上下文断言消息。

这是我的旧代码,适用于 ShouldlyShouldly 中包含源级信息和调用站点上下文断言错误:

[Fact]
public void Dict_should_contain_valid_Foobar_Bar_entry()
{
    IDictionary<String,Bar> dict = ...
    dict.TryGetValue( "Foobar", out Bar bar ).ShouldBeTrue();
    bar.ShouldNotBeNull();
    bar.ChildList.Count.ShouldBe( expected: 3 );
    bar.Message.ShouldBeNull();
}

[Fact]
public void Dict_should_contain_valid_Barbaz_Bar_entry()
{
    IDictionary<String,Bar> dict = ...
    dict.TryGetValue( "Barbaz", out Bar bar ).ShouldBeTrue();
    bar.ShouldNotBeNull();
    bar.ChildList.Count.ShouldBe( expected: 3 );
    bar.Message.ShouldBeNull();
}

我在同一个项目中将它转换为这个新的扩展方法:
public static void ShouldBeValidBar( this IDictionary<String,Bar> dict, String barName )
{
    dict.ShouldNotBeNull();
    dict.TryGetValue( barName, out Bar bar ).ShouldBeTrue();
    bar.ShouldNotBeNull();
    bar.ChildList.Count.ShouldBe( expected: 3 );
    bar.Message.ShouldBeNull();
}

所以我的测试变成了这样:
[Fact]
public void Dict_should_contain_valid_Foobar_Bar_entry()
{
    IDictionary<String,Bar> dict = ...
    dict.ShouldBeValidBar( "Foobar" );
}

[Fact]
public void Dict_should_contain_valid_Barbaz_Bar_entry()
{
    IDictionary<String,Bar> dict = ...
    dict.ShouldBeValidBar( "Barbaz" );
}

...但现在我的应该断言消息不包含来自 Dict_should_contain_valid_Foobar_Bar_entry 的任何上下文信息而是只包含来自 ShouldBeValidBar 的上下文.

如何指导Shouldly忽略 ShouldBeValidBar 的上下文并改用其父调用站点?

最佳答案

特尔;博士:

添加 [ShouldlyMethods]属性到您的自定义断言扩展方法 类(class) (不是单独的扩展方法):

[ShouldlyMethods] // <-- This, right here!
public static class MyShouldlyAssertions
{
    public static void ShouldBeValidBar( this IDictionary<String,Bar> dict, String barName )
    {
        [...]
    }
}

长版:

经过一番谷歌搜索,and reading articles about how Shouldly works - 阅读后the source of Shouldly's secret-sauce: SourceCodeTextGetter ,我看到它决定了堆栈跟踪中的哪些条目可以忽略 by the presence of the [ShouldlyMethods] attribute ( Shouldly.ShouldlyMethodsAttribute ) 在堆栈跟踪的每一帧中的方法包含类型:
void ParseStackTrace(StackTrace trace)
{
    [...]

    while (ShouldlyFrame == null || currentFrame.GetMethod().IsShouldlyMethod())
    {
        if (currentFrame.GetMethod().IsShouldlyMethod())
            ShouldlyFrame = currentFrame;

        [...]
    }

    [...]
}
internal static bool IsShouldlyMethod(this MethodBase method)
{
    if (method.DeclaringType == null)
        return false;

    return
        method
            .DeclaringType
            .GetCustomAttributes( typeof(ShouldlyMethodsAttribute), true )
            .Any()
        ||
        (
            method.DeclaringType.DeclaringType != null
            && 
            method
                .DeclaringType
                .DeclaringType
                .GetCustomAttributes( typeof(ShouldlyMethodsAttribute), true )
                .Any()
        );
}

所以只需添加 [ShouldlyMethods]属性到我的扩展方法的容器类:
[ShouldlyMethods]
public static class ShouldlyAssertionExtensions
{    
    public static void ShouldBeValidBar( this IDictionary<String,Bar> dict, String barName )
    {
        dict.ShouldNotBeNull();
        dict.TryGetValue( barName, out Bar bar ).ShouldBeTrue();
        bar.ShouldNotBeNull();
        bar.ChildList.Count.ShouldBe( expected: 3 );
        bar.Message.ShouldBeNull();
    }
}

现在我的断言错误具有 ShouldBeValidBar 的调用站点的上下文.欢呼!

关于c# - 如何使用应有的自定义断言并维护特定于调用站点的断言消息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61626283/

相关文章:

c# - 如何在 Visual Studio 2008/2010 中捕获并保存解决方案项目的编译时和运行时错误

c - C 中的 protected 函数调用

c++ - 优化、断言和 Release模式

c# - Ajax 请求后 .NET 后端的奇怪响应

C#:将子项添加到集合并在同一调用中设置子项的父项

c# - 在 nunit 测试中使用连接字符串

javascript - 类型错误 : parsed is undefined on angularjs service unit test

Python 单元测试 : AttributeError: no attribute 'assertTrue' when running on Linux

c# - 通过验证创建有效的日期时间对象

java - Jersey-test-framework 无用的回溯 JerseyTest