2009-02-21 4 views
1

Решение этой ошибки ускользнуло меня на несколько дней, и пришло время прийти за помощью. Короткий вариант: у меня есть единичный тест, который терпит неудачу на сервере сборки, но нет другой среды.Ошибка при проверке NUnit при запуске через CC.NET

Метод, который я тестирую, является методом расширения для ILog в log4net. Цель этого метода расширения - сделать журнал отладки текущего метода при вызове и использовать его для отладки. Код для этого довольно прост.

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.

Это хорошо работает в моей среде разработки, Visual Studio 2008 с TestDriven.NET. Он отлично работает, если я запускаю тест через nunit-console.exe или nunit-gui. Он даже работает хорошо, если я использую свой скрипт NAnt для выполнения теста.

Однако мой сервер сборки не прошел этот тест, когда он проходит через NAnt, который выполняется с CruiseControl.NET. Когда я запускаю его вручную с помощью 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 делает это предположение?

Я не получаю нигде с этой ошибкой, так как не могу воссоздать ее на моей машине разработки. Я рад за весь вход, который я могу получить.

Спасибо!

Микаэль Лундин

ответ

2

Похоже CallingMethod был оптимизирован далеко на сервере сборки. Когда вы повторили тест вручную, действительно ли вы использовали точно такую ​​же сборку?

0

Это CallingMethod может быть оптимизировано, это то, о чем я не думал. Позвольте мне провести еще несколько тестов.

Сначала я вызываю nant вручную на сервере сборки.

"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 вручную на нем.

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.

Это задача cc.net, которую я использую для выполнения сценария сборки NAnt.

<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 в моем скрипте сборки немного беспорядочна.

<!-- 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, чтобы определить, что это не является проблемой, как это? Я просто указываю компиляцию непосредственно в файл csproj. Должна ли msbuild не выбирать оптимизационную конфигурацию?

Благодарим вас за все ваши данные! Mikael Lundin

0

Я решил.

Удалено CallingMethod из моего кода и позволяет тестам напрямую обращаться к SUT. Это делает тестовый код немного уродливым, но он работает.

По-прежнему не знаю, почему CallingMethod изменил свое имя при запуске через CC.NET. Я думаю, это будет для кого-то еще, чтобы понять.

Смежные вопросы