You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VS2022中MS Test单元测试调试正常但常规运行失败排查

问题:VS2022中MS Test单元测试字符串断言调试正常但运行失败

在VS2022使用MS Test进行单元测试时,遇到如下问题:使用Assert.AreEqual比较两个字符串值时,调试模式下执行正常,但常规运行测试时断言失败。原以为.NET原生字符串比较无需重写Equals方法,但调试与运行结果不一致,求原因分析。

测试代码

<TestMethod()> Public Sub ShouldReturnaPIItemOfMWEqualTo1_ReadyForHttpSend()

    Try

        Dim da = New LVDataLoader
        Dim ana As New Analogue
        Dim anas As New Analogues
        Dim inp As New LVItem
        Dim expected As String = "0.0012"
        Dim result As String = ""

        inp.TransformerId = "1"
        inp.InstrumentId = "1"
        inp.SubjectAssetId = "1"
        inp.SubjectAssetName = "L1 section of Feeder: 1"
        inp.EngUnit = "MW L1"
        inp.Value = "1201.1999499999999"

        result = da.GetPIItem(inp).Value.ToString

        Assert.AreEqual(expected, result)
    Catch ex As Exception
        Throw
    End Try

End Sub

被调用的LVDataLoader.GetPIItem方法

Public Function GetPIItem(ByVal lvItem As LVItem) As PIItem

    Dim piitem As New PIItem
    Dim licArea As String
    Dim tagName As String
    Dim typeCode As String
    Dim ana As New Analogue
    Dim clnEngUnit As String

    Try

        'First determine the license area for this item we do so by looking up the transformer id in the substation list
        licArea = Right(GetSubstation(lvItem.TransformerId).LicenceArea, 1)

        'Determine the typecode for the engineering unit in question
        'by comparing the engineering unit passed to the engineering unit property
        'in the list of digitals.
        If IsDigital(lvItem.EngUnit, Digitals) Then
            typeCode = _digitalTypeCode
        Else
            typeCode = _analogueTypeCode
        End If

        'Now build the tag name
        clnEngUnit = mutl.GetNthElement(lvItem.EngUnit, " ", 1)
        tagName = licArea & "~" & _voltage & "~" &
                       lvItem.TransformerId & "~" &
                       lvItem.InstrumentId & "-" & lvItem.SubjectAssetId & "~" &
                       lvItem.SubjectAssetName & "~" &
                       lvItem.EngUnit & "~" & typeCode

        piitem.TagAttribute = _tagAttribute
        piitem.TagRef = tagName
        piitem.TagName = tagName
        piitem.TimeStamp = lvItem.Time
        piitem.Quality = "192"
        piitem.Value = Math.Round(ana.Convert(clnEngUnit, lvItem.Value, _analogues), 5)
        piitem.ServerName = _destDatabase

        Return piitem
    Catch ex As Exception
        Throw
    End Try

End Function

原因分析

这种调试与运行结果不一致的问题,核心原因并非字符串Equals方法的问题,而是浮点数值转换为字符串时的格式/精度差异,具体可能有以下几点:

  • 浮点精度与ToString默认格式差异:piitem.Value是Math.Round处理后的Double类型,调用无参数ToString()时,调试模式(JIT优化关闭)和运行模式(JIT优化开启)下,.NET对浮点数的字符串输出可能存在细微差别。比如调试时可能显示更贴合视觉的简化格式,而运行时可能因优化保留了更多隐含精度,导致ToString结果包含多余小数位(例如实际是0.0012000000001,ToString后变成"0.0012000000001",和预期的"0.0012"不匹配)。

  • 文化区域差异:ToString()默认使用当前线程的文化设置,调试时你的开发环境可能是英文文化(小数点为.),但测试运行时可能使用了其他文化(比如某些欧洲文化用,作为小数点分隔符),导致字符串格式直接不匹配。

  • JIT优化导致的计算差异:调试模式下JIT优化被禁用,浮点数计算的中间步骤会保留更多精度;而运行时开启JIT优化后,编译器可能对浮点运算进行优化,导致最终结果出现微小精度偏差,转换为字符串后就会触发断言失败。

解决方案

针对这类问题,推荐以下几种解决方式:

  1. 直接比较数值而非字符串
    避免将浮点数值转换为字符串再比较,直接比较数值本身,并指定允许的误差范围(浮点数本身存在精度限制,不能直接用绝对相等):

    Dim expectedValue As Double = 0.0012
    Dim resultValue As Double = Convert.ToDouble(da.GetPIItem(inp).Value)
    Assert.AreEqual(expectedValue, resultValue, 0.00001) ' 允许0.00001的误差
    
  2. 固定ToString的输出格式
    在转换字符串时显式指定格式,确保调试和运行时输出一致:

    result = da.GetPIItem(inp).Value.ToString("F4") ' 强制保留4位小数
    
  3. 统一测试的文化区域
    在测试方法开头设置固定的文化,避免因环境文化差异导致格式问题:

    System.Threading.Thread.CurrentThread.CurrentCulture = New System.Globalization.CultureInfo("en-US")
    System.Threading.Thread.CurrentThread.CurrentUICulture = New System.Globalization.CultureInfo("en-US")
    

内容的提问来源于stack exchange,提问作者Paul Johnson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:50:26