VisualStudio NUnit3TestAdapter测试项目与第三方dll

时间:2017-01-10 16:41:23

标签: c# visual-studio nunit-3.0

我有一个带有两个nuget包的测试项目Proj_Test

<packages>
  <package id="NUnit" version="3.6.0" targetFramework="net45" />
  <package id="NUnit3TestAdapter" version="3.6.0" targetFramework="net45" />
</packages>

Proj_Test引用了测试项目ProjLayout

Proj引用了其他几个需要加载的dll。 我在哪里可以添加此信息,以便我可以在IDE中使用NUnit3TestAdapter启动测试,而无需将dll实际复制到输出文件夹。

a solution for the Nunit2 Runners。但是当我尝试通过NUnit3TestAdapter将其用于Nunit3时,我失败了。

根据tips and tricks section我通过菜单添加了设置文件Test.runsettings

<RunSettings>
  <NUnit>
    <PrivateBinPath>D:\Drive\AnyThirdParty</PrivateBinPath>
  </NUnit>
</RunSettings>

设置似乎被忽略了。

如何为我的测试管理这些依赖项?

编辑: This is我发生了什么事。

  

专用程序集部署在与应用程序相同的目录结构中。如果为PrivateBinPath指定的目录不在ApplicationBase下,则忽略它们。

创建副本真的是唯一的解决方案吗?

2 个答案:

答案 0 :(得分:1)

如果找不到更好的东西,请尝试自行解决

using ConsoleApplication6;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Reflection;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestInitialize]
        public void Init()
        {
           AppDomain currentDomain = AppDomain.CurrentDomain;
           currentDomain.AssemblyResolve += MyResolveEventHandler;
        }

        [TestMethod]
        public void TestMethod1() { Assert.AreEqual(new MyClass().DoSomething(), 1); }

        [TestMethod]
        public void TestMethod2() { Assert.AreEqual(new MyClass().DoSomething(), 1); }

        private Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
        {
            return Assembly.LoadFile(@"C:\MyPath\MyAssembly.dll");
        }
    }
}

不幸的是,程序集探测仅适用于子目录,因此您无法使用它...

答案 1 :(得分:1)

感谢George Vovos的回答,这就是我最终实施的目标。

using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;

//https://github.com/nunit/docs/wiki/SetUpFixture-Attribute
//A SetUpFixture outside of any namespace provides SetUp and TearDown for the entire assembly.

[SetUpFixture]
class GlobalSetup
{

    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int SetDllDirectory(string NewDirectory);

    static HashSet<string> directories = new HashSet<string>
    {
        @"D:\Drive\AnyThirdParty\"
    };

    [OneTimeSetUp]
    public void RunBeforeAnyTests()
    {
        AddManagedHandler();
        SetNativeDirectories();
    }

    private void SetNativeDirectories()
    {
        if(directories.Count() != 1)
        {
            //TODO: add support for multiple directories
            throw new NotImplementedException("current implementation only supports exactly one directory");
        }

        if (0 == SetDllDirectory(directories.First()))
        {
            throw new Exception("SetDllDirectory failed with error " + Marshal.GetLastWin32Error());
        }
    }

    private void AddManagedHandler()
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    }

    private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        IEnumerable<string> candidates = FindCandidates(new AssemblyName(args.Name));
        return Assembly.LoadFrom(candidates.First());
    }

    private static IEnumerable<string> FindCandidates(AssemblyName assemblyname)
    {
        List<string> candidates = new List<string>();
        foreach (var path in directories)
        {
            string candidate = string.Format(@"{0}{1}.dll", path, assemblyname.Name);
            if (File.Exists(candidate))
            {
                candidates.Add(candidate);
            }
        }
        if (!candidates.Any())
        {
            throw new FileNotFoundException(string.Format("Can not find assembly: '{0}.dll'", assemblyname.Name));
        }
        return candidates;
    }
}