OpenCover On Cake script does not detect coverage on my Owin.Testing usage applying HttpPArameterBiding to some ApiController action parameter.
I have Created a new type of my ApiController that as an action with my ParameterBindingAttribute that I called FromHeaderAttribute. After that I created my Owin Test Server and respective HttpClient and did the requests and the proper asserts to validate that the Binding is working properly. The tests pass with sucess.
This is my unit tests Cake Task
Task("UnitTests")
.IsDependentOn("Build")
.IsDependentOn("RestoreNugets")
.DoesForEach(GetFiles($"{testsPath}/**/*.csproj"), (file) =>
{
var openCoverSettings = new OpenCoverSettings
{
OldStyle = true,
MergeOutput = true,
Register = "user",
LogLevel = OpenCoverLogLevel.Verbose,
ArgumentCustomization = args => args.Append("-coverbytest:*.Tests.dll").Append("-mergebyhash")
}
.WithFilter("+[AppRootName.*]*");
var projectName = file.GetFilename().ToString().Replace(".csproj",string.Empty);
var dotNetTestSettings = new DotNetCoreTestSettings
{
Configuration = "Release",
DiagnosticOutput = true,
Verbosity = DotNetCoreVerbosity.Normal,
ArgumentCustomization = (args)=>
{
args.Append($"--logger \"trx;LogFileName={projectName}-TestsResults.trx\"");
args.Append("--filter \"TestCategory=Unit|Category=Unit\"");
return args;
}
};
OpenCover(context => context.DotNetCoreTest(file.FullPath, dotNetTestSettings), new FilePath($"CoverageResults.xml"), openCoverSettings);
})
.Finally(()=>
{
Information($"Copying test reports to ${outputDir}/TestsResults .... ");
CopyFiles($"{testsPath}/**/TestResults/*.trx",$"{outputDir}/TestsResults");
ReportGenerator($"*-CoverageResults.xml", $"{outputDir}/Reports");
});
this is my XUnit test:
[Fact]
[Trait("Category", "Unit")]
public async Task WhenHeadersArePresent_SettingsShouldBeSetted()
{
HttpConfiguration configuration = new HttpConfiguration();
var container = new SimpleInjector.Container();
Mock<IApiControllerValidation> mockValidationInterface = new Mock<IApiControllerValidation>();
ManualResetEvent resetEvent = new ManualResetEvent(false);
Settings settingsReceived = null;
mockValidationInterface.Setup((validator) => validator.Assert(It.IsAny<object>(), It.IsAny<object>(), It.IsAny<IDictionary<string, string>>(), It.IsAny<IHttpActionResult>()))
.Callback<object, object, IDictionary<string, string>, IHttpActionResult>((header, body, parameters, result) =>
{
settingsReceived = header as Settings;
resetEvent.Set();
});
container.RegisterInstance(mockValidationInterface.Object);
using (var server = TestServer.Create(app =>
{
configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
configuration.MapHttpAttributeRoutes();
app.Use((owinContext, nextHandler)=> nextHandler());
app.UseWebApi(configuration);
}))
{
var client = server.HttpClient;
client.DefaultRequestHeaders.Add("header1", new List<string>() { "headervalue1" } );
client.DefaultRequestHeaders.Add("header2", new List<string>() { "headervalue2" });
var result = await client.PostAsync<Payload>("optionalHeader", new Payload("value1"), new JsonMediaTypeFormatter());
Assert.Equal(HttpStatusCode.OK,result.StatusCode);
};
resetEvent.WaitOne();
Assert.NotNull(settingsReceived);
Assert.Equal("headervalue1", settingsReceived.Header1);
Assert.Equal("headervalue2", settingsReceived.Header2);
}
And this is my Api Action were I want to test the FromHEader attribute that I have implement.
[HttpPost]
[Route("optionalHeader",Name = "PostValidation")]
public IHttpActionResult OptionalHeaders([FromHeader]Settings settings, [FromBody]Payload payload)
{
var result = Ok();
validation.Assert(settings,payload, null, result);
return result;
}
I expect that the code coverage of the test detects the usage of This type but its not because the report is showing 0 code coverage on my type.
I figured out what was the problem, and it was not related to anything related to asp.net framework HttpParameterBinding component.
instead of execute the code cover like this:
OpenCover(context => context.DotNetCoreTest(file.FullPath, dotNetTestSettings), new FilePath($"CoverageResults.xml"), openCoverSettings);
I changed that to be like this:
OpenCover(tool => {
tool.XUnit2($"{testsPath}/**/**/**/**/{projectName}.dll",xUnit2Settings);
}, new FilePath("./OpenCoverCoverageResults.xml"),openCoverSettings);
Also the Build must be done with configuration in debug mode so the OpenCover can use the pdbs.
The only thing that I still dont like is the path to the dlls to be explicit by the number of levels that are explicit and I also did not want to copy the dlls because that will take more time.