visual-studio 如何使用 Visual Studio 测试中资源文件中的特定异常消息测试预期异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/113395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I test for an expected exception with a specific exception message from a resource file in Visual Studio Test?
提问by Alex Duggleby
Visual Studio Test can check for expected exceptions using the ExpectedException attribute. You can pass in an exception like this:
Visual Studio 测试可以使用 ExpectedException 属性检查预期的异常。您可以传入这样的异常:
[TestMethod]
[ExpectedException(typeof(CriticalException))]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
You can also check for the message contained within the ExpectedException like this:
您还可以检查包含在 ExpectedException 中的消息,如下所示:
[TestMethod]
[ExpectedException(typeof(CriticalException), "An error occured")]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
But when testing I18N applications I would use a resource file to get that error message (any may even decide to test the different localizations of the error message if I want to, but Visual Studio will not let me do this:
但是在测试 I18N 应用程序时,我会使用资源文件来获取该错误消息(如果我愿意,任何人甚至可能决定测试错误消息的不同本地化,但 Visual Studio 不会让我这样做:
[TestMethod]
[ExpectedException(typeof(CriticalException), MyRes.MultipleOrganisationsNotAllowed)]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
The compiler will give the following error:
编译器会报如下错误:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute
属性参数必须是属性的常量表达式、typeof 表达式或数组创建表达式
Does anybody know how to test for an exception that has a message from a resource file?
有人知道如何测试具有来自资源文件的消息的异常吗?
One option I have considered is using custom exception classes, but based on often heard advice such as:
我考虑过的一种选择是使用自定义异常类,但基于经常听到的建议,例如:
"Do create and throw custom exceptions if you have an error condition that can be programmatically handled in a different way than any other existing exception. Otherwise, throw one of the existing exceptions." Source
“如果您有一个错误条件,可以以不同于任何其他现有异常的方式以编程方式处理,请创建并抛出自定义异常。否则,抛出现有异常之一。” 来源
I'm not expecting to handle the exceptions differently in normal flow (it's a critical exception, so I'm going into panic mode anyway) and I don't think creating an exception for each test case is the right thing to do. Any opinions?
我不希望在正常流程中以不同的方式处理异常(这是一个严重的异常,所以无论如何我都会进入恐慌模式)并且我不认为为每个测试用例创建一个异常是正确的做法。有什么意见吗?
采纳答案by Simon Buchan
Justan opinion, but I would say the error text:
只是一个意见,但我会说错误文本:
- is part of the test, in which case getting it from the resource would be 'wrong' (otherwise you could end up with a consistantly mangled resource), so just update the test when you change the resource (or the test fails)
- is not part of the test, and you should only care that it throws the exception.
- 是测试的一部分,在这种情况下,从资源中获取它会是“错误的”(否则您最终可能会得到一个一致损坏的资源),因此只需在更改资源时更新测试(或测试失败)
- 不是测试的一部分,您应该只关心它抛出异常。
Note that the first option should let you test multiple languages, given the ability to run with a locale.
请注意,第一个选项应该让您测试多种语言,因为它可以使用语言环境运行。
As for multiple exceptions, I'm from C++ land, where creating loads and loads of exceptions (to the point of one per 'throw' statement!) in big heirachies is acceptable (if not common), but .Net's metadata system probably doesn't like that, hence that advice.
至于多个异常,我来自 C++ 领域,在大继承中创建负载和异常负载(每个“抛出”语句一个!)是可以接受的(如果不常见),但 .Net 的元数据系统可能不会不喜欢那样,因此有那个建议。
回答by Daniel Plaisted
I would recommend using a helper method instead of an attribute. Something like this:
我建议使用辅助方法而不是属性。像这样的东西:
public static class ExceptionAssert
{
public static T Throws<T>(Action action) where T : Exception
{
try
{
action();
}
catch (T ex)
{
return ex;
}
Assert.Fail("Exception of type {0} should be thrown.", typeof(T));
// The compiler doesn't know that Assert.Fail
// will always throw an exception
return null;
}
}
Then you can write your test something like this:
然后你可以写你的测试是这样的:
[TestMethod]
public void GetOrganisation_MultipleOrganisations_ThrowsException()
{
OrganizationList organizations = new Organizations();
organizations.Add(new Organization());
organizations.Add(new Organization());
var ex = ExceptionAssert.Throws<CriticalException>(
() => organizations.GetOrganization());
Assert.AreEqual(MyRes.MultipleOrganisationsNotAllowed, ex.Message);
}
This also has the benefit that it verifies that the exception is thrown on the line you were expecting it to be thrown instead of anywhere in your test method.
这还有一个好处,它可以验证异常是否在您期望抛出的行上而不是在您的测试方法中的任何地方抛出。
回答by user53794
The ExpectedException Message argument does not match against the message of the exception. Rather this is the message that is printed in the test results if the expected exception did not in fact occur.
ExpectedException Message 参数与异常消息不匹配。如果预期的异常实际上没有发生,则这是在测试结果中打印的消息。
回答by cruizer
I think you can just do an explicit try-catch in your test code instead of relying on the ExpectedException attribute to do it for you. Then you can come up with some helper method that will read the resource file and compare the error message to the one that comes with the exception that was caught. (of course if there wasn't an exception then the test case should be considered a fail)
我认为你可以在你的测试代码中做一个显式的 try-catch 而不是依赖 ExpectedException 属性来为你做。然后你可以想出一些帮助方法来读取资源文件并将错误消息与捕获的异常附带的错误消息进行比较。(当然,如果没有异常,那么测试用例应该被认为是失败的)
回答by Jedidja
If you switch over to using the very nice xUnit.Nettesting library, you can replace [ExpectedException] with something like this:
如果你切换到使用非常好的xUnit.Net测试库,你可以用这样的东西替换 [ExpectedException]:
[Fact]
public void TestException()
{
Exception ex = Record.Exception(() => myClass.DoSomethingExceptional());
// Assert whatever you like about the exception here.
}
回答by Gishu
I wonder if NUnit is moving down the path away from simplicity... but here you go.
我想知道 NUnit 是否正在远离简单性……但是你走了。
New enhancements (2.4.3 and up?) to the ExpectedException attribute allow you more control on the checks to be performed on the expected Exception via a Handler method. More Details on the official NUnit doc page.. towards the end of the page.
对 ExpectedException 属性的新增强功能(2.4.3 及更高版本?)允许您通过 Handler 方法更好地控制对预期异常执行的检查。在官方 NUnit 文档页面上的更多详细信息.. 在页面末尾。
[ExpectedException( Handler="HandlerMethod" )]
public void TestMethod()
{
...
}
public void HandlerMethod( System.Exception ex )
{
...
}
Note: Something doesn't feel right here.. Why are your exceptions messages internationalized.. Are you using exceptions for things that need to be handled or notified to the user. Unless you have a bunch of culturally diverse developers fixing bugs.. you shouldn't be needing this. Exceptions in English or a common accepted language would suffice. But in case you have to have this.. its possible :)
注意:这里有些不对劲.. 为什么您的异常消息要国际化.. 您是否对需要处理或通知用户的事情使用异常。除非你有一群不同文化的开发人员在修复错误......你不应该需要这个。英语或普遍接受的语言的例外就足够了。但万一你必须有这个..它可能:)
回答by Peter Bernier
I came across this question while trying to resolve a similar issue on my own. (I'll detail the solution that I settled on below.)
我在尝试自己解决类似问题时遇到了这个问题。(我将在下面详细介绍我确定的解决方案。)
I have to agree with Gishu's comments about internationalizing the exception messages being a code smell.
我必须同意 Gishu 关于将异常消息国际化为代码异味的评论。
I had done this initially in my own project so that I could have consistency between the error messages throw by my application and in my unit tests. ie, to only have to define my exception messages in one place and at the time, the Resource file seemed like a sensible place to do this since I was already using it for various labels and strings (and since it made sense to add a reference to it in my test code to verify that those same labels showed in the appropriate places).
我最初是在我自己的项目中这样做的,这样我就可以在我的应用程序和单元测试中抛出的错误消息之间保持一致性。即,只需要在一个地方和时间定义我的异常消息,资源文件似乎是一个明智的地方,因为我已经将它用于各种标签和字符串(并且因为添加引用是有意义的在我的测试代码中添加到它以验证那些相同的标签显示在适当的位置)。
At one point I had considered (and tested) using try/catch blocks to avoid the requirement of a constant by the ExpectedException attribute, but this seemed like it would lead to quite a lot of extra code if applied on a large scale.
有一次我曾考虑(并测试)使用 try/catch 块来避免 ExpectedException 属性对常量的要求,但这似乎如果大规模应用会导致相当多的额外代码。
In the end, the solution that I settled on was to create a static class in my Resource library and store my exception messages in that. This way there's no need to internationalize them (which I'll agree doesn't make sense) and they're made accessible anytime that a resource string would be accessible since they're in the same namespace. (This fits with my desire not to make verifying the exception text a complex process.)
最后,我确定的解决方案是在我的资源库中创建一个静态类并将我的异常消息存储在其中。这样就不需要将它们国际化(我同意这没有意义)并且它们可以在资源字符串可访问的任何时候访问,因为它们位于同一名称空间中。(这符合我不想让验证异常文本成为一个复杂过程的愿望。)
My test code then simply boils down to (pardon the mangling...):
我的测试代码然后简单地归结为(请原谅这个错误......):
[Test,
ExpectedException(typeof(System.ArgumentException),
ExpectedException=ProductExceptionMessages.DuplicateProductName)]
public void TestCreateDuplicateProduct()
{
_repository.CreateProduct("TestCreateDuplicateProduct");
_repository.CreateProduct("TestCreateDuplicateProduct");
}

