未涵盖 C# 8.0 单元测试开关表达式
C# 8.0 unit test switch expression not covered
我正在为我的项目使用支持 switch 表达式的 C# 8.0。我最近正在构建一个单元测试项目并生成代码覆盖率报告。但是好像所有的switch表达式都有问题。我的代码中有一些类似于以下内容的行:
private static string GenerateRequestUrl(Language language, WeatherDataType dataType) {
var url = "https://data.weather.gov.hk/weatherAPI/opendata/weather.php?";
url += language switch {
Language.English => "lang=en",
Language.TraditionalChinese => "lang=tc",
Language.SimplifiedChinese => "lang=sc",
_ => "lang=en"
};
url += dataType switch {
WeatherDataType.LocalWeatherForecast => "&dataType=flw",
WeatherDataType.NineDaysWeather => "&dataType=fnd"
};
return url;
}
而我的测试方法涵盖了上述所有情况,但报告显示未涵盖那些带有switch表达式的行。就像这张图片:
Coverage Highlights in JetBrains Rider
我应该怎么做才能覆盖它们。
虽然这可能不是您希望的答案,但似乎代码覆盖率不适用于 non-sequential switch 表达式。
当您查看 IL 代码时,新的 C# 8.0 switch 表达式首先计算(跳转)哪个表达式为真,然后设置 url。
而顺序 switch 语句在 case 语句之后设置 url。
因此,如果您想要全面覆盖,您应该使用顺序 switch 语句(例如下面代码中的 WeatherDataType)。
代码
IL 代码
.method public hidebysig static string GenerateRequestUrl(valuetype Demo.Generator/Language language,
valuetype Demo.Generator/WeatherDataType dataType) cil managed
{
// Code size 130 (0x82)
.maxstack 2
.locals init (string V_0,
string V_1,
string V_2,
valuetype Demo.Generator/WeatherDataType V_3,
valuetype Demo.Generator/WeatherDataType V_4,
string V_5)
IL_0000: nop
IL_0001: ldstr "https://data.weather.gov.hk/weatherAPI/opendata/we"
+ "ather.php\?"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ldc.i4.1
IL_000a: brtrue.s IL_000d
IL_000c: nop
IL_000d: ldarg.0
IL_000e: switch (
IL_0021,
IL_0029,
IL_0031)
IL_001f: br.s IL_0039
IL_0021: ldstr "lang=en"
IL_0026: stloc.2
IL_0027: br.s IL_0041
IL_0029: ldstr "lang=tc"
IL_002e: stloc.2
IL_002f: br.s IL_0041
IL_0031: ldstr "lang=sc"
IL_0036: stloc.2
IL_0037: br.s IL_0041
IL_0039: ldstr "lang=en"
IL_003e: stloc.2
IL_003f: br.s IL_0041
IL_0041: ldc.i4.1
IL_0042: brtrue.s IL_0045
IL_0044: nop
IL_0045: ldloc.1
IL_0046: ldloc.2
IL_0047: call string [System.Runtime]System.String::Concat(string,
string)
IL_004c: stloc.0
IL_004d: ldarg.1
IL_004e: stloc.s V_4
IL_0050: ldloc.s V_4
IL_0052: stloc.3
IL_0053: ldloc.3
IL_0054: brfalse.s IL_005e
IL_0056: br.s IL_0058
IL_0058: ldloc.3
IL_0059: ldc.i4.1
IL_005a: beq.s IL_006c
IL_005c: br.s IL_007a
IL_005e: ldloc.0
IL_005f: ldstr "&dataType=flw"
IL_0064: call string [System.Runtime]System.String::Concat(string,
string)
IL_0069: stloc.0
IL_006a: br.s IL_007a
IL_006c: ldloc.0
IL_006d: ldstr "&dataType=fnd"
IL_0072: call string [System.Runtime]System.String::Concat(string,
string)
IL_0077: stloc.0
IL_0078: br.s IL_007a
IL_007a: ldloc.0
IL_007b: stloc.s V_5
IL_007d: br.s IL_007f
IL_007f: ldloc.s V_5
IL_0081: ret
} // end of method Generator::GenerateRequestUrl
我正在为我的项目使用支持 switch 表达式的 C# 8.0。我最近正在构建一个单元测试项目并生成代码覆盖率报告。但是好像所有的switch表达式都有问题。我的代码中有一些类似于以下内容的行:
private static string GenerateRequestUrl(Language language, WeatherDataType dataType) {
var url = "https://data.weather.gov.hk/weatherAPI/opendata/weather.php?";
url += language switch {
Language.English => "lang=en",
Language.TraditionalChinese => "lang=tc",
Language.SimplifiedChinese => "lang=sc",
_ => "lang=en"
};
url += dataType switch {
WeatherDataType.LocalWeatherForecast => "&dataType=flw",
WeatherDataType.NineDaysWeather => "&dataType=fnd"
};
return url;
}
而我的测试方法涵盖了上述所有情况,但报告显示未涵盖那些带有switch表达式的行。就像这张图片: Coverage Highlights in JetBrains Rider
我应该怎么做才能覆盖它们。
虽然这可能不是您希望的答案,但似乎代码覆盖率不适用于 non-sequential switch 表达式。
当您查看 IL 代码时,新的 C# 8.0 switch 表达式首先计算(跳转)哪个表达式为真,然后设置 url。
而顺序 switch 语句在 case 语句之后设置 url。
因此,如果您想要全面覆盖,您应该使用顺序 switch 语句(例如下面代码中的 WeatherDataType)。
代码
IL 代码
.method public hidebysig static string GenerateRequestUrl(valuetype Demo.Generator/Language language,
valuetype Demo.Generator/WeatherDataType dataType) cil managed
{
// Code size 130 (0x82)
.maxstack 2
.locals init (string V_0,
string V_1,
string V_2,
valuetype Demo.Generator/WeatherDataType V_3,
valuetype Demo.Generator/WeatherDataType V_4,
string V_5)
IL_0000: nop
IL_0001: ldstr "https://data.weather.gov.hk/weatherAPI/opendata/we"
+ "ather.php\?"
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ldc.i4.1
IL_000a: brtrue.s IL_000d
IL_000c: nop
IL_000d: ldarg.0
IL_000e: switch (
IL_0021,
IL_0029,
IL_0031)
IL_001f: br.s IL_0039
IL_0021: ldstr "lang=en"
IL_0026: stloc.2
IL_0027: br.s IL_0041
IL_0029: ldstr "lang=tc"
IL_002e: stloc.2
IL_002f: br.s IL_0041
IL_0031: ldstr "lang=sc"
IL_0036: stloc.2
IL_0037: br.s IL_0041
IL_0039: ldstr "lang=en"
IL_003e: stloc.2
IL_003f: br.s IL_0041
IL_0041: ldc.i4.1
IL_0042: brtrue.s IL_0045
IL_0044: nop
IL_0045: ldloc.1
IL_0046: ldloc.2
IL_0047: call string [System.Runtime]System.String::Concat(string,
string)
IL_004c: stloc.0
IL_004d: ldarg.1
IL_004e: stloc.s V_4
IL_0050: ldloc.s V_4
IL_0052: stloc.3
IL_0053: ldloc.3
IL_0054: brfalse.s IL_005e
IL_0056: br.s IL_0058
IL_0058: ldloc.3
IL_0059: ldc.i4.1
IL_005a: beq.s IL_006c
IL_005c: br.s IL_007a
IL_005e: ldloc.0
IL_005f: ldstr "&dataType=flw"
IL_0064: call string [System.Runtime]System.String::Concat(string,
string)
IL_0069: stloc.0
IL_006a: br.s IL_007a
IL_006c: ldloc.0
IL_006d: ldstr "&dataType=fnd"
IL_0072: call string [System.Runtime]System.String::Concat(string,
string)
IL_0077: stloc.0
IL_0078: br.s IL_007a
IL_007a: ldloc.0
IL_007b: stloc.s V_5
IL_007d: br.s IL_007f
IL_007f: ldloc.s V_5
IL_0081: ret
} // end of method Generator::GenerateRequestUrl