C# 如何单元测试使用正确的可本地化格式化字符串调用记录器?

C# 如何单元测试使用正确的可本地化格式化字符串调用记录器?,c#,.net,unit-testing,C#,.net,Unit Testing,在我正在测试的应用程序中,我希望确保针对某些输入调用记录器。某些方法可能有不同的记录器消息(例如“值格式不正确”、“值超出范围”)。因此,我希望确保使用正确的消息调用记录器 自己保存的记录器字符串位于RESX中,将来可能会本地化。此外,措辞可能会改变。因此,只要与硬编码字符串进行比较,就会在文本更改时中断相关测试。由于它们是可本地化的,这意味着我必须强制单元测试在特定的文化下执行,或者有更好的方法吗 更复杂的是,RESX字符串实际上并不像上面那样简单,而是形式为“第{0}行:{2}列的值{1}格

在我正在测试的应用程序中,我希望确保针对某些输入调用记录器。某些方法可能有不同的记录器消息(例如“值格式不正确”、“值超出范围”)。因此,我希望确保使用正确的消息调用记录器

自己保存的记录器字符串位于RESX中,将来可能会本地化。此外,措辞可能会改变。因此,只要与硬编码字符串进行比较,就会在文本更改时中断相关测试。由于它们是可本地化的,这意味着我必须强制单元测试在特定的文化下执行,或者有更好的方法吗

更复杂的是,RESX字符串实际上并不像上面那样简单,而是形式为
“第{0}行:{2}列的值{1}格式不正确。”
然后将其用作string.Format()的输入,以生成
“第12行:第45列的值'12a.45'格式不正确。”
。这是记录器实际获取的字符串。我应该把这个字符串硬编码到单元测试中吗

编辑:

我将尝试更详细地解释,用一种非常简化的方法来说明我的意思:

public void ConvertSomething(object value)
{
    if (/* Check if valid value */)
    {
        var convertedValue = /* Some conversion */ ;
        if (/* Check is in range */)
        {
            // Do something
        }
        else
        {
            Logger.Log(string.Format(Resources.OutOfRange, LineNumber, convertedValue));
        }
    }
    else
    {
        Logger.Log(string.Format(Resources.InvalidValue, LineNumber, value, ColumnNumber));
    }
}
如何测试使用正确消息调用记录器?我不能简单地检查是否有人打电话给记录器。如果我给它一个有效但超出范围的值,但有效性检查有一个bug,它将调用记录器,但带有消息“invalid value”,而实际上它应该是“超出范围”


我可以模拟记录器,这样我就可以看到它被调用了,参数是什么。但是我应该反对什么呢?

您可以更改代码中线程的当前区域性(如果计算机上存在该区域性)。如果它不存在,您需要安装/创建它

至于比较应用程序中使用的字符串(可能会改变),我建议不要将其作为测试的目标

相反,可能在每个静态资源中都有一个健全的测试字符串,并对此进行测试。如果这种情况随着区域性的变化而变化,那么您已经加载了正确的资源,并且可以安全地假定其余内容也正确

NUnit支持更改测试线束的区域性:

更新:我明白了,问题是测试无法查看记录器?我建议您要么模拟一个日志程序,而不知道它正在被测试,并且包含它自己的断言,要么放弃测试日志程序本身,测试当前是否在区域性更改中加载了附属程序集。如果记录器仅使用资源文件,则.NET运行时将处理正确文件或基本区域性文件的默认加载

然后,您可以进行单独的测试,以显示记录器记录了什么,而不必担心它记录了什么,因为这在另一个测试中有所涉及

更新2:我想我知道你在做什么了。是否有可能让记录器接受字符串格式和
params object[]args
,以便在使用特定值插入字符串之前访问该字符串

或者,是否可以使字符串保持静态,或者它本质上改变了每个测试运行?如果测试本身首先负责播种值,则测试中硬编码值是有效的。另外,对于文化,我将分别讨论这些更改,以及选择不同消息的不同代码路径所引入的更改

更新3:对不起,我看不到树木的树木。测试本身可以从代码使用的resx文件中构建预期的字符串,并且只插入硬编码的值。这取决于每次运行的测试输出没有差异


如果resx发生了变化,那么只要插入格式化字符串的值的数量没有变化,您就不需要修复代码或测试。

您创建了一个假的记录器,并监视它,以便您的代码在需要时调用它

我认为这是一个集成,甚至是QA级别的测试。我甚至不确定如何让机器以可靠的方式交换语言。问题是我已经遇到过这样的情况:SUT走错了执行路径,因此产生了错误的消息。我给了它一个超出范围(但有效)的值,但它记录为“畸形”。测试是绿色的(因为调用了记录器),但是消息是错误的,所以应该是红色的。我有一个假的记录器,可以看到调用了什么(以及使用了什么参数)。但是,记录器会得到
“第12行:第45列的值'12a.45'格式不正确。”
例如,它是由包含string.Format()占位符的RESX字符串生成的。我应该在测试中硬编码结果字符串吗?或者有更好的方法吗?有更好的方法,让它记录一个测试值,该值在不同的文化中不同,但关键是从创建时起不会改变,这样您的测试就可以保持静态。如果单元测试在代码中产生差异,那么让单元测试管理区域性是完全有效的。我的理解是,您不是在测试字符串,而是在测试记录器是否侦听区域性。请参阅我的编辑。我想测试字符串(或者至少区分正在使用的字符串)。我(至少目前)不想为了更简单的测试而使记录器接口复杂化。这意味着每个实现都需要首先执行string.Format()。字符串有点静态,即LineNumber的值(例如)是在类的构造函数中设置的属性。所以我可以陈述我认为文本应该是什么。但是我是否应该在测试中编写这样一个静态文本,然后每次更新RESX时都需要更新它?我已经有一个假的记录器,可以看到它正在被调用。但是,我对记录器可能有不同的调用