首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过CC.NET运行时NUnit测试失败

通过CC.NET运行时NUnit测试失败
EN

Stack Overflow用户
提问于 2009-02-21 21:14:24
回答 3查看 1.9K关注 0票数 1

这个错误的解决方案我已经想了好几天了,是时候来这里寻求帮助了。简而言之,我有一个在构建服务器上失败的单元测试,但没有其他环境。

我正在测试的方法是log4net中ILog的一个扩展方法。此扩展方法的目的是在调用时生成当前方法的调试日志,我将其用于调试。执行此操作的代码非常简单。

代码语言:javascript
复制
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 mock模拟ILog接口,并让IsDebugEnabled返回true。

请考虑以下NUnit测试方法。

代码语言:javascript
复制
[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);
}

如果我通过nunit-console.exe或nunit-gui运行测试,它在我的开发环境--带有TestDriven.NET的Visual Studio2008中执行得很好。如果我使用我的NAnt脚本执行测试,它甚至可以很好地运行。

但是,当我的构建服务器通过从CruiseControl.NET执行的NAnt运行时,它无法通过此测试。当我在构建服务器上使用nunit-console.exe手动运行它时,它成功了。

错误和堆栈跟踪如下。

代码语言:javascript
复制
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做出了这个假设?

因为我不能在我的开发机器上重新创建它,所以我没有得到这个错误。我为我能得到的所有输入感到高兴。

谢谢!

Mikael Lundin

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-02-21 21:49:24

看起来CallingMethod已经在构建服务器上进行了优化。当您手动重复测试时,您真的使用了完全相同的程序集吗?

票数 2
EN

Stack Overflow用户

发布于 2009-02-22 09:15:12

CallingMethod可能会被优化掉,这是我没有想到的。让我对此再运行几个测试。

首先,我在构建服务器上手动调用nant。

代码语言:javascript
复制
"C:\Program Files\nant-0.86-beta1\bin\nant.exe" test -D:nunit.exe.path="C:\\Program Files\\NUnit 2.4.8\bin\\" -D:Artifact.Output.Path="D:\\Build\\Mint\\Artifacts\\" -D:msbuild.logger="C:\\Program Files\\CruiseControl.NET\\server\\ThoughtWorks.CruiseControl.MSBuild.dll" -D:fxcop.exe.path="C:\\Program Files\\Microsoft FxCop 1.36\\"

这工作得很好,测试不会失败!我转到生成的二进制文件,并在其上手动执行NUnit。

代码语言:javascript
复制
D:\Build\Mint\WorkingDirectory\Source\Test\Vanilla.UnitTests\bin\Debug>"C:\Program Files\NUnit 2.4.8\bin\nunit-console.exe" Vanilla.UnitTests.dll
NUnit version 2.4.8
Copyright (C) 2002-2007 Charlie Poole.
Copyright (C) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov.
Copyright (C) 2000-2002 Philip Craig.
All Rights Reserved.

Runtime Environment -
   OS Version: Microsoft Windows NT 5.2.3790 Service Pack 2
  CLR Version: 2.0.50727.3082 ( Net 2.0.50727.3082 )

..............................................................
Tests run: 62, Failures: 0, Not run: 0, Time: 7.891 seconds

它的工作方式应该是这样的。但是,当我通过CC.NET强制构建时,测试失败,如上面所示。然后,如果我选择构建服务器生成的二进制文件,并在这些文件上运行NUnit,那么我就成功了。

因此,二进制文件不会更改,但测试是否成功取决于NAnt是通过命令行还是通过CC.NET运行的。

这是我用来执行NAnt构建脚本的cc.net任务。

代码语言:javascript
复制
<nant>
    <executable>C:\Program Files\nant-0.86-beta1\bin\nant.exe</executable>
    <buildArgs>-D:nunit.exe.path="C:\\Program Files\\NUnit 2.4.8\bin\\" -D:Artifact.Output.Path="D:\\Build\\Mint\\Artifacts\\" -D:msbuild.logger="C:\\Program Files\\CruiseControl.NET\\server\\ThoughtWorks.CruiseControl.MSBuild.dll" -D:fxcop.exe.path="C:\\Program Files\\Microsoft FxCop 1.36\\"</buildArgs>
    <nologo>true</nologo>
    <buildFile>Mint.build</buildFile>
    <targetList>
        <target>clean</target>
        <target>build</target>
        <target>test</target>
        <target>staticAnalysis</target>
    </targetList>
    <buildTimeoutSeconds>1200</buildTimeoutSeconds>
</nant>

在我的构建脚本中执行NUnit的任务有点混乱。

代码语言:javascript
复制
<!-- Run all tests -->
<target name="test" description="Run NUnit tests" depends="build">
  <property name="Failed.Test.Count" value="0"/>

  <!-- Test Vanilla -->
  <property name="Test.Name" value="Vanilla.UnitTests" />
  <call target="runCurrentTest" />

  <fail if="${int::parse(Failed.Test.Count)>0}" message="Failures reported in unit tests" />
</target>

<!-- Utility method to run tests -->
<target name="runCurrentTest">      
  <exec program="${nunit.exe.path}nunit-console.exe"
      failonerror="false"
      resultproperty="Test.Result"
      verbose="true">
      <arg value="${Test.Path + Test.Name + '\bin\Debug\' + Test.Name}.dll" />
      <arg value="/xml:${Artifact.Output.Path + Test.Name}-nunit-results.xml" />
      <arg value="/nologo" />
  </exec>
  <property name="Failed.Test.Count" value="${int::parse(Test.Result) + int::parse(Failed.Test.Count)}"/>
</target>

我可以显式地在msbuild exec调用上设置优化标志,以确定它不是这样的问题吗?我确实将编译直接指向csproj文件。msbuild不应该从中选择优化配置吗?

感谢您的所有投入!Mikael Lundin

票数 0
EN

Stack Overflow用户

发布于 2009-02-22 11:23:36

我解决了。

从我的代码中删除了CallingMethod,让测试直接调用SUT。它使测试代码看起来有点丑陋,但它是有效的。

我还是不知道为什么在运行CC.NET的时候CallingMethod会改名,我想这得由别人来弄明白了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/573759

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档