Reputation: 4350
Is there a way to unit test or debug a web api in one vs solution? I am consuming the WebAPI using HttpClient and have two instances of VS up to do this.
in 1 VS instance I have the unit test, in the second vs instance I have the webapi running in localhost.
Is there a better way to do this?
Is the preferred way to unit test is to have a reference to the WebAPI project?
I want to consume it using httpClient and not have to reference it in the UnitTest Project.
so in my UnitTest method it would have a baseAddress of "http://localhost:1234"
this would be where the WebAPI if launched from the same solution would be hosted.
The current way I am debugging requires me to launch a second Visual Studio instance with the same solution loaded and have one running the WebAPI project, while the other Visual Studio runs the Unit Test project.
Upvotes: 19
Views: 15942
Reputation: 2572
I try the selft hosted but I get some problens 1.
HttpContext.Current is null
IisExpress solution work for me very good
bathe file to deploy to 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
I work with 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();
}
}
attach to iisexpress
Debug test then make a breakpoint
goto Debug>Attach to process>
in the attach to select
click OK,
search iisexpress and click attach
Upvotes: 0
Reputation: 9604
In the current version of ASP.Net Core the official solution to this is to use the Microsoft.AspNetCore.TestHost Nuget assembly which creates a simulated web server hosting the web project in the test project.
Details on usage can be found here: https://learn.microsoft.com/en-us/aspnet/core/testing/integration-testing
On the one hand it feels like a bit of a fudge because by what definition is it genuine integration testing if a real web server is not involved, on the other hand it does at least work pretty seamlessly once you get it set up.
Upvotes: 0
Reputation: 6434
Upvotes: 20
Reputation: 203
So a colleague and I just tried the suggested answers to no avail. However, we have actually found a solution to this that works well by attaching to the IIS process once you are in debug mode on your test. Here are the steps:
For extra ease, we downloaded an extension for attaching to IIS automatically which gave us a menubar item in the Tools menu.
For superb ease we customized the toolbar section to add the menubar command to the toolbar so that attaching to IIS was one simple click.
Upvotes: 7
Reputation: 7285
If you have an API project and you created an end-to-end unit test project for the API (meaning you are testing the API directly using HttpClient, WebClient, or other http client wrappers), you have to enable "Multiple startup projects" on the solution. Follow steps below:
Upvotes: 0
Reputation: 6054
You can self host the web api as mike mentioned,
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();
}
for more details, http://www.asp.net/web-api/overview/older-versions/self-host-a-web-api
you could start the hosting when you initialize your unit test suite, and shutdown when you cleanup the test suite.
Upvotes: 1
Reputation: 6520
As Daniel Mann stated, this isn't unit testing. This is integration testing. You are running up the entire project and testing everything.
If you want to unit test you webapi controllers, just add a unit test project to webapi project and create unit tests. You want to focus on testing only a single class at a time. Mock/Fake any dependencies of that class.
Here's a nice example from Microsoft http://www.asp.net/web-api/overview/testing-and-debugging/unit-testing-with-aspnet-web-api
but if what you are looking for is running the test you have in a single solution. Just put both projects in the same solution. Right click on the solution in the solution explorer. Select "Set StartUp projects." select "multiple startup projects" and select the projects you want to startup at the same time.
Upvotes: 4