这个错误的解决方案已经让我好几天了,现在是时候来这里寻求帮助了。简短的版本是,我有一个在构建服务器上失败但没有其他环境的单元测试。
我正在测试的方法是 log4net 中 ILog 的扩展方法。此扩展方法的目的是在调用时制作当前方法的调试日志,并使用它进行调试。执行此操作的代码非常简单。
public static void MethodHead(this ILog log, params object[] parameters)
{
/* Assert */
log.AssertNonNull();
/* Since this is an expensive operation, don't do it if Debug is not enabled */
if (log.IsDebugEnabled)
{
StackTrace stackTrace = new StackTrace();
/* Get calling method */
MethodBase method = stackTrace.GetFrame(1).GetMethod();
string logMessage = string.Format("{0}.{1}({2})", method.DeclaringType.Name, method.Name, parameters.ToDelimitedString(", "));
log.Debug(logMessage);
}
}
在这种方法中,我检查是否启用了调试模式,因为如果不应该记录任何内容(由于性能问题),我不想执行 StackTrace。当我测试这个方法时,我将使用 Rhino Mocks 来模拟 ILog 接口并让 IsDebugEnabled 返回 true。
请考虑以下 NUnit 测试方法。
[Test(Description = "Verify that MethodHead extension method will log with calling class.method(arguments)")]
public void MethodHeadShouldLogCurrentMethodNameWithArguments()
{
/* Setup */
MockRepository mocks = new MockRepository();
ILog log = mocks.CreateMock<ILog>();
string[] arguments = new string[] { "CAT", "IN", "A", "HAT" };
string logMessage = string.Format("{0}.{1}({2})",
"MethodHeadTest", "CallingMethod", arguments.ToDelimitedString(", "));
With.Mocks(mocks).Expecting(delegate
{
/* Record */
Expect.Call(log.IsDebugEnabled).Return(true);
Expect.Call(delegate { log.Debug(logMessage); });
})
.Verify(delegate
{
/* Verify */
CallingMethod(log, arguments);
});
}
private void CallingMethod(ILog log, params object[] arguments)
{
log.MethodHead(arguments);
}
这在我的开发环境(带有 TestDriven.NET 的 Visual Studio 2008)中执行良好。如果我通过 nunit-console.exe 或 nunit-gui 运行测试,它确实执行得很好。如果我使用我的 NAnt 脚本执行测试,它甚至运行良好。
但是,我的构建服务器在通过从 CruiseControl.NET 执行的 NAnt 运行时未能通过此测试。当我在构建服务器上使用 nunit-console.exe 手动运行它时,它会成功。
错误和堆栈跟踪如下。
Rhino.Mocks.Exceptions.ExpectationViolationException : ILog.Debug("**<>c__DisplayClass8.<MethodHeadShouldLogCurrentMethodNameWithArguments>b__5**(CAT, IN, A, HAT)"); Expected #0, Actual #1.
ILog.Debug("MethodHeadTest.CallingMethod(CAT, IN, A, HAT)"); Expected #1, Actual #0.
at Rhino.Mocks.MethodRecorders.UnorderedMethodRecorder.DoGetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
at Rhino.Mocks.MethodRecorders.MethodRecorderBase.GetRecordedExpectation(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
at Rhino.Mocks.Impl.ReplayMockState.DoMethodCall(IInvocation invocation, MethodInfo method, Object[] args)
at Rhino.Mocks.Impl.ReplayMockState.MethodCall(IInvocation invocation, MethodInfo method, Object[] args)
at Rhino.Mocks.MockRepository.MethodCall(IInvocation invocation, Object proxy, MethodInfo method, Object[] args)
at Rhino.Mocks.Impl.RhinoInterceptor.Intercept(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at ILogProxy86e676a4761d4509b43a354c1aba33ed.Debug(Object message)
at Vanilla.Extensions.LogExtensions.MethodHead(ILog log, Object[] parameters) in d:\Build\Mint\WorkingDirectory\Source\Main\Vanilla\Extensions\LogExtensions.cs:line 42
at Vanilla.UnitTests.Extensions.LogExtensions.MethodHeadTest.<>c__DisplayClass8.<MethodHeadShouldLogCurrentMethodNameWithArguments>b__5() in d:\Build\Mint\WorkingDirectory\Source\Test\Vanilla.UnitTests\Extensions\LogExtensions\MethodHeadTest.cs:line 99
at Rhino.Mocks.With.FluentMocker.Verify(Proc methodCallsToBeVerified)
at Vanilla.UnitTests.Extensions.LogExtensions.MethodHeadTest.MethodHeadShouldLogCurrentMethodNameWithArguments() in d:\Build\Mint\WorkingDirectory\Source\Test\Vanilla.UnitTests\Extensions\LogExtensions\MethodHeadTest.cs:line 90
所以问题是构建服务器认为这个方法有另一个(动态的?)名称。或者更确切地说,是 Rhino Mocks 做出了这个假设?
由于无法在我的开发机器上重新创建它,因此我无法解决此错误。我很高兴我能得到所有的意见。
谢谢!
迈克尔·伦丁