The solution for this error has escaped me for several days now, and it is time to come here for help. The short version is, I have a unit test that fails on the build server but no other environment.
The method I'm testing is an extension method for ILog in log4net. The purpose of this extension method is to make a debug log of the current method, when called and I use it for debugging. The code to do this is pretty straight forward.
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);
}
}
In this method I check that debug mode is enabled, because I don't want to do StackTrace if nothing is supposed to get logged (because of performance issues). When I test this method I will use Rhino Mocks to mock the ILog interface and let IsDebugEnabled return true.
Please consider following NUnit test method.
[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);
}
This executes well in my development environment, Visual Studio 2008 with TestDriven.NET. It does execute well if I run the test through nunit-console.exe or nunit-gui. It even runs well if I use my NAnt script to execute the test.
However, my build server fails this test when it runs through NAnt which is executed from CruiseControl.NET. When I run it manually with nunit-console.exe on the build server it succeeds.
The error and stack trace are the following.
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
So the problem is that the build server thinks that this method has another (dynamic?) name. Or rather it is Rhino Mocks that makes this assumption?
I don't get anywhere with this error since I can't recreate it on my development machine. I'm happy for all input I can get.
Thank you!
Mikael Lundin