NUnit и параллельная библиотека задач конфликтуют в Mono

У меня возникает странный сбой при объединении NUnit и TPL в Mono. Вот код:

using System;
using NUnit.Engine;

namespace BadMono
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Mono is bad.");
            DryRun();
        }

        private static void DryRun()
        {
            // Code based on:
            // http://stackoverflow.com/questions/33826500/how-to-run-a-nunit-test

            string path = @"<snip>/bin/Debug/TestChannelA.dll";

            TestPackage package = new TestPackage(path);
            package.AddSetting("WorkDirectory", Environment.CurrentDirectory);

            // prepare the engine
            ITestEngine engine = TestEngineActivator.CreateInstance();

            // ERROR happens on this line
            var _filterService = engine.Services.GetService<ITestFilterService>();
        }
    }
}

Я добавил следующие пакеты NuGet:

NUnit.Engine v3.2.0
NUnit v3.2.0
Microsoft.Tpl.Dataflow v4.5.24

Поэтому, если я запускаю этот код в Windows 10 (.NET 4.6.1), программа печатает «Моно — это плохо». без сбоев.

Я компилирую в Visual Studio 2015, а затем тестирую в Linux, используя моно. Если я запускаю это в Linux (OpenSUSE 13.2), я получаю эту трассировку стека:

BadMono/bin/Debug $ mono BadMono.exe
Mono is bad.

Unhandled Exception:
Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
  at Mono.Cecil.BaseAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name, Mono.Cecil.ReaderParameters parameters) <0x41f5df10 + 0x00333> in <filename unknown>:0 
  at Mono.Cecil.BaseAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name) <0x41f5dec0 + 0x0003e> in <filename unknown>:0 
  at Mono.Cecil.DefaultAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name) <0x41f5d890 + 0x00073> in <filename unknown>:0 
  at Mono.Cecil.MetadataResolver.Resolve (Mono.Cecil.TypeReference type) <0x41f5d530 + 0x000f3> in <filename unknown>:0 
  at Mono.Cecil.ModuleDefinition.Resolve (Mono.Cecil.TypeReference type) <0x41f5d2a0 + 0x0002a> in <filename unknown>:0 
  at Mono.Cecil.TypeReference.Resolve () <0x41f5d240 + 0x00033> in <filename unknown>:0 
  at NUnit.Engine.Internal.CecilExtensions.GetAttribute (Mono.Cecil.TypeDefinition type, System.String fullName) <0x41f5a300 + 0x000b6> in <filename unknown>:0 
  at NUnit.Engine.Services.ExtensionService.FindExtensionsInAssembly (System.String assemblyName, Boolean specifiedInConfig) <0x41f46f80 + 0x0032f> in <filename unknown>:0 
  at NUnit.Engine.Services.ExtensionService.FindExtensionsInDirectory (System.IO.DirectoryInfo startDir) <0x41f46b10 + 0x00177> in <filename unknown>:0 
  at NUnit.Engine.Services.ExtensionService.StartService () <0x41f45640 + 0x000ab> in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
  at Mono.Cecil.BaseAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name, Mono.Cecil.ReaderParameters parameters) <0x41f5df10 + 0x00333> in <filename unknown>:0 
  at Mono.Cecil.BaseAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name) <0x41f5dec0 + 0x0003e> in <filename unknown>:0 
  at Mono.Cecil.DefaultAssemblyResolver.Resolve (Mono.Cecil.AssemblyNameReference name) <0x41f5d890 + 0x00073> in <filename unknown>:0 
  at Mono.Cecil.MetadataResolver.Resolve (Mono.Cecil.TypeReference type) <0x41f5d530 + 0x000f3> in <filename unknown>:0 
  at Mono.Cecil.ModuleDefinition.Resolve (Mono.Cecil.TypeReference type) <0x41f5d2a0 + 0x0002a> in <filename unknown>:0 
  at Mono.Cecil.TypeReference.Resolve () <0x41f5d240 + 0x00033> in <filename unknown>:0 
  at NUnit.Engine.Internal.CecilExtensions.GetAttribute (Mono.Cecil.TypeDefinition type, System.String fullName) <0x41f5a300 + 0x000b6> in <filename unknown>:0 
  at NUnit.Engine.Services.ExtensionService.FindExtensionsInAssembly (System.String assemblyName, Boolean specifiedInConfig) <0x41f46f80 + 0x0032f> in <filename unknown>:0 
  at NUnit.Engine.Services.ExtensionService.FindExtensionsInDirectory (System.IO.DirectoryInfo startDir) <0x41f46b10 + 0x00177> in <filename unknown>:0 
  at NUnit.Engine.Services.ExtensionService.StartService () <0x41f45640 + 0x000ab> in <filename unknown>:0 

Вот версия Mono, которую я использую:

$ mono --version
Mono JIT compiler version 4.4.0 (Stable 4.4.0.40/f8474c4 Wed Mar 30 18:05:27 PDT 2016)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug 
        LLVM:          supported, not enabled.
        GC:            sgen

Нечетное исправление №1. Если я закомментирую следующую строку, программа будет нормально работать в Linux/mono:

private static void DryRun()
{
    ... // other code the same

    // If I comment out this SINGLE LINE, the program works fine.
    // var _filterService = engine.Services.GetService<ITestFilterService>();
}

Нечетное исправление №2

Скажем теперь, что я оставляю код таким, каким он был изначально (без комментария к строке _filterService). Если я удалю один файл .dll в рабочем каталоге, у меня не будет сбоя. Покажу исходные файлы:

<snip>BadMono/bin/Debug $ ls
 .
 ..
 BadMono.exe
 BadMono.exe.config
 BadMono.pdb
 BadMono.vshost.exe
 BadMono.vshost.exe.config
 Mono.Cecil.dll
 System.Threading.Tasks.Dataflow.dll
 System.Threading.Tasks.Dataflow.xml
 nunit-agent-x86.exe
 nunit-agent.exe
 nunit.engine.api.dll
 nunit.engine.dll
 nunit.framework.dll
 nunit.framework.xml

Теперь, если я удалю System.Threading.Tasks.Dataflow.dll, программа снова работает нормально. Windows не проявляет этой проблемы и прекрасно работает в любых обстоятельствах, которые я описываю; проблема только в моно/линукс.

Это действительно странно для меня, потому что я даже не вызываю ничего из Tasks.Dataflow (TPL) в этом примере кода. Может кто-нибудь пролить свет на то, что здесь происходит, пожалуйста?


person Matthew Kraus    schedule 01.04.2016    source источник
comment
У вас установлен пакет mono-devel?   -  person svick    schedule 02.04.2016
comment
@svick Да, но это версия 3.0.6-3.1.3, предназначенная для openSUSE 13.1. Я скомпилировал моно 4.4.0 из исходного кода и установил префикс для установки на пользовательский путь. Я поместил этот путь в переменную среды PATH, чтобы версия, которую я собрал из исходников, была найдена перед версией для openSUSE.   -  person Matthew Kraus    schedule 04.04.2016