我使用NUnit / MSTest编写集成测试,只是因为它更容易。测试需要在同一解决方案中与TCP服务器通信,并且它要调试测试和TCP服务器。有没有办法在调试模式下从解决方案启动项目(控制台应用程序)并同时调试测试方法?无论我怎样尝试VS都不会允许我。
答案 0 :(得分:4)
这是编写集成测试时的常见情况。集成测试依赖于另一个要启动和运行的服务。为了解决这个问题,我通常会调用启动过程来启动它。 ConsoleApplication项目在同一解决方案中。只需添加一个帮助程序类即可调用该进程。
internal class ProcessInvoker
{
/// <summary>
/// Invokes the host process for test service
/// </summary>
public static void InvokeDummyService()
{
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
ProcessStartInfo info = new ProcessStartInfo(Path.Combine(path, "DummyService.exe"));
info.UseShellExecute = true;
info.WorkingDirectory = path;
var process = Process.Start(info);
}
/// <summary>
/// Kills the process of service host
/// </summary>
public static void KillDummyService()
{
Process.GetProcessesByName("DummyService").ToList().ForEach(x => x.Kill());
}
}
现在,在TestInitialize和TestCleanup方法中,我将启动该进程并终止相应的进程。
/// <summary>
/// Setup required before the tests of the fixture will run.
/// </summary>
[TestFixtureSetUp]
public void Init()
{
ProcessInvoker.InvokeDummyService();
}
/// <summary>
/// Tear down to perform clean when the execution is finished.
/// </summary>
[TestFixtureTearDown]
public void TearDown()
{
ProcessInvoker.KillDummyService();
}
现在,参与此过程以进行调试。这非常棘手。我在Visual Studio团队中找到一个VS Addin来自动将子进程附加到当前调试器,但它似乎只适用于“f5”调试。
然后我发现了this SO post,它确实令人惊讶。我在这里发布了完整的代码,只需很少的自定义:
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.Generic;
using EnvDTE;
namespace Common
{
[ComImport, Guid("00000016-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
[PreserveSig]
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
[PreserveSig]
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}
public class MessageFilter : IOleMessageFilter
{
private const int Handled = 0, RetryAllowed = 2, Retry = 99, Cancel = -1, WaitAndDispatch = 2;
int IOleMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo)
{
return Handled;
}
int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
return dwRejectType == RetryAllowed ? Retry : Cancel;
}
int IOleMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
{
return WaitAndDispatch;
}
public static void Register()
{
CoRegisterMessageFilter(new MessageFilter());
}
public static void Revoke()
{
CoRegisterMessageFilter(null);
}
private static void CoRegisterMessageFilter(IOleMessageFilter newFilter)
{
IOleMessageFilter oldFilter;
CoRegisterMessageFilter(newFilter, out oldFilter);
}
[DllImport("Ole32.dll")]
private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
}
public static class AttachDebugger
{
public static void ToProcess(int processId)
{
MessageFilter.Register();
var process = GetProcess(processId);
if (process != null)
{
process.Attach();
Console.WriteLine("Attached to {0}", process.Name);
}
MessageFilter.Revoke();
}
private static Process GetProcess(int processID)
{
var dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.12.0");
var processes = dte.Debugger.LocalProcesses.OfType<Process>();
return processes.SingleOrDefault(x => x.ProcessID == processID);
}
}
}
注意:您需要从AddReference添加VS自动化库EnvDTE
- &gt;一些推广
现在在ProcessInvoker
类中在进程启动语句之后添加对AttachDebugger
实用程序类的调用。
var process = Process.Start(info);
// Add this after invoking process.
AttachDebugger.ToProcess(process.Id);
当我启动调试测试时,它就像魅力一样。该进程被调用,附加到VS并且能够调试其他进程代码。
查看工作解决方案here。特别是WcfDynamicProxy.Tests在解决方案中。我使用Nunit在那里编写集成测试。
答案 1 :(得分:0)
无法一次调试两个程序,但为什么需要在调试模式下运行Console app?只需在没有调试的情况下启动它,然后在调试模式下启动集成测试 - 如果您想在某个时刻调试控制台应用程序而不是测试方法,您可以启动Visual Studio的第二个实例并将调试器附加到控制台应用程序进程并从那里调试。
提示您也可以通过编程方式将调试程序附加到程序中调用Debuger.Launch()。