如何在一个解决方案中调试/单元测试webAPi

时间:2015-10-22 16:44:18

标签: c# visual-studio unit-testing asp.net-web-api2

有没有办法在一个vs解决方案中对web api进行单元测试或调试?我正在使用HttpClient使用WebAPI并且有两个VS实例来执行此操作。

在1个VS实例中我有单元测试,在第二个vs实例中我有在localhost中运行的webapi。

有更好的方法吗?

单元测试的首选方法是引用WebAPI项目吗?

我想使用httpClient来使用它,而不必在UnitTest项目中引用它。

所以在我的UnitTest方法中,它的baseAddress为“http://localhost:1234

这将是托管从同一解决方案启动的WebAPI的地方。

我正在调试的当前方式要求我启动第二个Visual Studio实例并加载相同的解决方案,并运行WebAPI项目,而另一个Visual Studio运行单元测试项目。

7 个答案:

答案 0 :(得分:8)

  1. 开始调试单元测试
  2. 在测试代码的第一行或调用本地web api项目之前
  3. 右键单击您的web api项目并调试>启动新实例

答案 1 :(得分:4)

Daniel Mann表示,这不是单元测试。这是集成测试。您正在运行整个项目并测试所有内容。

如果要对webapi控制器进行单元测试,只需将单元测试项目添加到webapi项目并创建单元测试。您希望一次只关注一个类。模拟/伪造该类的任何依赖项。

以下是Microsoft http://www.asp.net/web-api/overview/testing-and-debugging/unit-testing-with-aspnet-web-api

的一个很好的例子

但是如果您正在寻找的是在单一解决方案中运行测试。只需将两个项目放在同一个解决方案中。右键单击解决方案资源管理器中的解决方案。选择"设置启动项目。"选择"多个启动项目"并选择要同时启动的项目。

答案 2 :(得分:4)

所以一位同事和我刚试过建议的答案都无济于事。但是,我们实际上已经找到了一个解决方案,通过在测试时处于调试模式时附加到IIS进程,可以很好地解决这个问题。以下是步骤:

  1. 确保您的单元测试项目和Web API项目在同一解决方案中。
  2. 确保您的解决方案在属性部分设置为单启动(即默认保留)。
  3. 在控制器方法中为要调试的端点添加断点。
  4. 在测试中添加要调试的断点,然后右键单击并单击“调试测试”(或使用您最喜欢的测试运行器,如ReSharper进行调试)。
  5. 点击点后,单击Debug |附加到流程......
  6. 查找并单击给定服务的本地IIS进程,然后单击Attach
  7. 继续调试并在服务中查看断点
  8. 为了方便起见,我们下载了一个自动附加到IIS的扩展程序,它在“工具”菜单中为我们提供了一个菜单栏项。

    为了方便起见,我们自定义了工具栏部分,将menubar命令添加到工具栏中,以便只需点击一下即可附加到IIS。

答案 3 :(得分:1)

你可以像迈克提到的那样自我托管网络API,

var config = new HttpSelfHostConfiguration("http://localhost:8080");

config.Routes.MapHttpRoute(
    "API Default", "api/{controller}/{id}", 
    new { id = RouteParameter.Optional });

using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
    server.OpenAsync().Wait();
    Console.WriteLine("Press Enter to quit.");
    Console.ReadLine();
}

了解更多详情, http://www.asp.net/web-api/overview/older-versions/self-host-a-web-api

您可以在初始化单元测试套件时启动托管,并在清理测试套件时关闭。

答案 4 :(得分:0)

如果您有一个API项目并且您为API创建了一个端到端的单元测试项目(意味着您正在使用HttpClient,WebClient或其他http客户端包装器直接测试API),则必须启用&# 34;多个启动项目"在解决方案上。请按照以下步骤操作:

  1. 右键单击解决方案文件并选择属性。
  2. 选择"多个启动项目"单选按钮。
  3. 选择"开始" web api项目和单元测试项目下拉列表中的操作。
  4. F5以调试模式启动。
  5. 您将收到错误对话框"无法直接启动带有输出类型类库的项目"。这很好,因为单元测试项目只是一个类库(不是可执行文件,所以没有main / start方法)。只需点击"确定"对话框。
  6. 在您要测试的单元测试方法上,右键单击并选择" Debug Unit Tests"开始调试。

答案 5 :(得分:0)

在当前版本的ASP.Net Core中,官方解决方案是使用Microsoft.AspNetCore.TestHost Nuget程序集,该程序集在测试项目中创建托管Web项目的模拟Web服务器。

有关使用的详细信息,请访问: https://docs.microsoft.com/en-us/aspnet/core/testing/integration-testing

一方面它感觉有点像软糖,因为如果不涉及真正的网络服务器,它的真正集成测试是什么定义,另一方面,一旦你设置了它,它至少可以非常无缝地工作

答案 6 :(得分:0)

我尝试托管的selft,但是遇到了一些问题 1.

HttpContext.Current is null
  1. 我在网络api自定义错误处理程序中存在问题,并且在自托管状态下不起作用

IisExpress解决方案对我来说非常好

保存文件以部署到iis

@Echo off 
set msBuildDir=C:\Program Files (x86)\MSBuild\14.0\Bin
::compile web api project
call "%msBuildDir%\msbuild.exe" solutionFilePath.sln /t:projectName /p:Configuration=Debug;TargetFrameworkVersion=v4.5 /l:FileLogger,Microsoft.Build.Engine;logfile=Manual_MSBuild_ReleaseVersion_LOG.log /p:Platform="Any CPU" /p:BuildProjectReferences=false

call "C:\Program Files (x86)\IIS Express\iisexpress.exe" /path:"pathToRootOfApiProject" /port:8888 /trace:error 

我正在使用Nunit frameWork

  [SetUpFixture]
    public class SetUpTest
    {
        private Process process = null;
        private Process IisProcess = null;
        private System.IO.StreamWriter sw = null;
        string programsFilePath = Environment.GetEnvironmentVariable(@"PROGRAMFILES(X86)");

        [OneTimeSetUp]
        public void Initialize()
        {
            //compile web api project
            List<string> commands = new List<string>();
            commands.Add($@"CD {programsFilePath}\MSBuild\14.0\Bin\");
            commands.Add($@"msbuild ""pathToYourSolution.sln"" /t:ProjrctName /p:Configuration=Debug;TargetFrameworkVersion=v4.5 /p:Platform=""Any CPU"" /p:BuildProjectReferences=false /p:VSToolsPath=""{programsFilePath}\MSBuild\Microsoft\VisualStudio\v14.0""");
            RunCommands(commands);

            //deploy to iis express
            RunIis();
        }



        [OneTimeTearDown]
        public void OneTimeTearDown()
        {
            if (IisProcess.HasExited == false)
            {
                IisProcess.Kill();
            }
        }

        void RunCommands(List<string> cmds, string workingDirectory = "")
        {
            if (process == null)
            {
                InitializeCmd(workingDirectory);
                sw = process.StandardInput;
            }

            foreach (var cmd in cmds)
            {
                sw.WriteLine(cmd);
            }
        }

        void InitializeCmd(string workingDirectory = "")
        {
            process = new Process();
            var psi = new ProcessStartInfo();
            psi.FileName = "cmd.exe";
            psi.RedirectStandardInput = true;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            psi.WorkingDirectory = workingDirectory;
            process.StartInfo = psi;
            process.Start();
            process.OutputDataReceived += (sender, e) => { Debug.WriteLine($"cmd output: {e.Data}"); };
            process.ErrorDataReceived += (sender, e) => { Debug.WriteLine($"cmd output: {e.Data}"); throw new Exception(e.Data); };
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }

        void RunIis()
        {
            string _port = System.Configuration.ConfigurationManager.AppSettings["requiredPort"];
            if (_port == 0)
            {
                throw new Exception("no value by config setting for 'requiredPort'");
            }

            IisProcess = new Process();
            var psi = new ProcessStartInfo();
            psi.FileName = $@"{programsFilePath}\IIS Express\iisexpress.exe";
            psi.Arguments = $@"/path:""pathToRootOfApiProject"" /port:{_port} /trace:error";
            psi.RedirectStandardInput = true;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            IisProcess.StartInfo = psi;
            IisProcess.Start();
            IisProcess.OutputDataReceived += (sender, e) => { Debug.WriteLine($"cmd output: {e.Data}"); };
            IisProcess.ErrorDataReceived += (sender, e) =>
            {
                Debug.WriteLine($"cmd output: {e.Data}");
                if (e.Data != null)
                {
                    throw new Exception(e.Data);
                }
            };
            IisProcess.BeginOutputReadLine();
            IisProcess.BeginErrorReadLine();
        }
    }

附加到iisexpress

调试测试,然后创建一个断点 转到调试>附加到进程> 在附件中选择 enter image description here 单击确定,

搜索iisexpress,然后单击附加