在调试模式下运行单元测试时,如何调用多个启动项目

时间:2011-02-14 15:15:50

标签: unit-testing visual-studio-2010 resharper

这似乎是一件简单的事情,但我似乎无法在任何地方找到任何信息!我有一个解决方案,它有一个服务,我们在调试时在'控制台模式'下运行。我希望它从Visual Studio运行我的单元测试时启动并“附加”。

我正在使用Resharper作为单元测试运行器。

1 个答案:

答案 0 :(得分:1)

不能直接回答你的问题,但是 我们最近遇到了类似的问题,最终使用AppDomain

解决了问题

由于您的解决方案已作为控制台项目运行,因此在新的AppDomain中启动它几乎不会有任何作用。此外,您可以在此项目上运行Assertions以及单元测试的一部分。 (如果需要)

考虑以下静态类Sandbox,您可以使用它来启动多个应用程序域。 Execute方法需要一个类型为-SandboxAction。 (课程定义也包括在下面)

您首先扩展此类并提供用于运行控制台项目的任何启动操作。

public class ConsoleRunnerProjectSandbox : SandboxAction
{
  protected override void OnRun()
    {
         Bootstrapper.Start(); //this code will be run on the newly create app domain
    }

}

现在,只需致电

,即可让您的应用域运行
Sandbox.Execute<ConsoleRunnerProjectSandbox>("AppDomainName", configFile)

请注意,您可以将此调用传递给配置文件,以便您可以像运行控制台一样启动项目

请再问一些问题。

public static class Sandbox
{
    private static readonly List<Tuple<AppDomain, SandboxAction>> _sandboxes = new List<Tuple<AppDomain, SandboxAction>>();

    public static T Execute<T>(string friendlyName, string configFile, params object[] args)
        where T : SandboxAction
    {
        Trace.WriteLine(string.Format("Sandboxing {0}: {1}", typeof (T).Name, configFile));

        AppDomain sandbox = CreateDomain(friendlyName, configFile);

        var objectHandle = sandbox.CreateInstance(typeof(T).Assembly.FullName, typeof(T).FullName, true, BindingFlags.Default, null, args, null, null, null);

        T sandBoxAction = objectHandle.Unwrap() as T;

        sandBoxAction.Run();


        Tuple<AppDomain, SandboxAction> box = new Tuple<AppDomain, SandboxAction>(sandbox, sandBoxAction);
        _sandboxes.Add(box);

        return sandBoxAction;
    }

    private static AppDomain CreateDomain(string name, string customConfigFile)
    {
        FileInfo info = customConfigFile != null ? new FileInfo(customConfigFile) : null;
        if (!string.IsNullOrEmpty(customConfigFile) && !info.Exists)
            throw new ArgumentException("customConfigFile not found using " + customConfigFile + " at " + info.FullName);

        var appsetup = new AppDomainSetup();
        //appsetup.ApplicationBase = Path.GetDirectoryName(typeof(Sandbox).Assembly.Location);
        appsetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
        if (customConfigFile==null)
            customConfigFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
        appsetup.ConfigurationFile = customConfigFile;

        var sandbox = AppDomain.CreateDomain(
            name,
            AppDomain.CurrentDomain.Evidence,
            appsetup);
        return sandbox;
    }

    public static void DestroyAppDomainForSandbox(SandboxAction action)
    {
        foreach(var tuple in _sandboxes)
        {
            if(tuple.Second == action)
            {
                AppDomain.Unload(tuple.First);
                Console.WriteLine("Unloaded sandbox ");
                _sandboxes.Remove(tuple);
                return;
            }
        }
    }
}


 [Serializable]
public abstract class SandboxAction : MarshalByRefObject
{
    public override object InitializeLifetimeService()
    {
        return null;
    }
    public void Run()
    {
        string name = AppDomain.CurrentDomain.FriendlyName;
        Log.Info("Executing {0} in AppDomain:{1} thread:{2}", name, AppDomain.CurrentDomain.Id, Thread.CurrentThread.ManagedThreadId);

        try
        {
            OnRun();
        }
        catch (Exception ex)
        {
            Log.Error(ex, "Exception in app domain {0}", name);
            throw;
        }
    }

    protected abstract void OnRun();

    public virtual void Stop()
    {
    }


}