如何设置ManagementException的ErrorCode?
-
06-07-2019 - |
题
我只想处理特定ErrorCode的ManagementException异常,并且在编写单元测试时遇到问题。通常,我会编写测试,以便它类似于以下内容:
Searcher search = MockRepository.GenerateMock<Searcher>();
// wrapper for ManagementObjectSearcher
...
search.Expect(s => s.Get()).Throw(new ManagementException());
...
但是,这并没有将ErrorCode设置为我想要的那个,实际上ManagementException没有设置此值的构造函数。
如何做到这一点?
(请注意,我使用的是RhinoMocks作为我的模拟框架,但我假设这是独立于框架的;我需要知道的是如何创建一个具有特定ErrorCode值的ManagementException。我也发现了一些引用一个 System.Management.ManagementException.ThrowWithExtendedInfo(ManagementStatus errorCode)
方法在线,但这似乎不公开访问。)
解决方案
克服这一障碍的最小努力将是一个静态帮助器/实用程序方法,它使用反射来破解所需错误代码中的插槽。使用最优秀的Reflector,我看到有一个私有的“errorCode”。 field,仅通过ManagementException中定义的内部ctors设置。所以:)
public static class EncapsulationBreaker
{
public static ManagementException GetManagementExceptionWithSpecificErrorCode(ManagementStatus statusToBeStuffed)
{
var exception = new ManagementException();
var fieldInfo = exception.GetType().GetField("errorCode",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.DeclaredOnly);
fieldInfo.SetValue(exception, statusToBeStuffed);
return exception;
}
}
验证它有效
[Test]
public void TestGetExceptionWithSpecifiedErrorCode()
{
var e = EncapsulationBreaker.GetManagementExceptionWithSpecificErrorCode(ManagementStatus.BufferTooSmall);
Assert.AreEqual(ManagementStatus.BufferTooSmall, e.ErrorCode);
}
虽然我通常对测试中的反思感到不满,但这是需要/有用的极少数情况之一。
HTH
其他提示
从ManagementException派生一个类并使用您自己的隐藏错误代码实现。让你的模拟返回这个课程。
有一个非常简单的小方法或类来捕获异常并从中获取错误代码,然后将其传递给执行工作的真正类。在测试中,将代码替换为直接传递给实际类,当您获得该错误代码时将通过该代码。
最明显的方法是对异常进行子类化,但是如果这不起作用,那么捕获它的代码会立即抛出你自己的异常,它允许你公开该代码,这将是另一种选择。
我会继承 ManagementException
,并在子类中覆盖 ErrorCode
getter(如果正常的保护级别阻止你这样做,也许内省可以让你更接近)。任何处理 ManagementException
但从未听说过您的特定子类的代码都应该处理您的子类“就像”毕竟,你试图为测试目的模拟 ManagementException
。
编辑:可以想象 ErrorCode
是不能被覆盖的(我讨厌过于严格的语言,他们可以用这种方式停止测试,但不能否认它们存在; - )。在这种情况下,依赖注入仍然可以为您节省 - DI是我最喜欢的测试模式之一。
DI的测试目的是将测试中的代码与可能抑制可测试性的严格假设分离 - 而这正是我们在这里所拥有的,尽管是一种不同寻常的形式。您正在测试的代码当前会执行 x.ErrorCode
以获取异常x的错误代码。很好,它必须改为 getErrorCode(x)
,其中 getErrorCode
是一个委托,它通常只是返回x.ErrorCode
;并且它必须具有 getErrorCode
委托的setter,以便出于测试目的,您可以将其更改为代理,该代理执行 return 23
(或任何错误代码值想要模拟测试)。
细节可以有所不同,但依赖注入可以(除其他外)有助于补偿你不可避免地从系统(或从你无法直接修改的其他库和c)中获得的对象中的某种过度刚性,如此示例