opencover icon indicating copy to clipboard operation
opencover copied to clipboard

Excludebyattribute not excluding the method

Open dwkane opened this issue 7 years ago • 11 comments

Please provide the following information when submitting an issue.

Where appropriate replace the [ ] with a [X]

My Framework

  • [ ] .NET 2
  • [ ] .NET 3.5
  • [ ] .NET 4
  • [ ] .NET 4.5
  • [ ] .NET 4.6
  • [ ] .NET 4.6.1
  • [ ] .NET 4.6.2
  • [X] .NET Core 1.0.0
  • [ ] Something else

My Environment

  • [ ] Windows 7 or below (not truly supported due to EOL)
  • [ ] Windows 8
  • [ ] Windows 8.1
  • [X] Windows 10
  • [ ] Windows 10 IoT Core
  • [ ] Windows Server 2012
  • [ ] Windows Server 2012 R2
  • [ ] Windows Server 2016

I have already...

  • [X] repeated the problem using the latest stable release of OpenCover.
  • [X] reviewed the usage guide and usage document.
  • [ ] have looked at the opencover output xml file in an attempt to resolve the issue.
  • [ ] reviewed the current issues to check that the issue isn't already known.

My issue is related to (check only those which apply):

  • [ ] no coverage being recorded
  • [ ] 32 or 64 bit support
  • [ ] feature request

Expected Behavior

I am expecting that when using an attribute on a method and then using the -excludebyattribute filter, that the entire method would be excluded from coverage reporting.

Actual Behavior

The line within the method is still reported as uncovered. See repro steps for details.

opencover

Steps to reproduce the problem:

OpenCover command: "%userprofile%\.nuget\packages\OpenCover\4.6.801\tools\OpenCover.Console.exe" -oldstyle -output:"opencover.xml" -register:user -target:"powershell.exe" -targetargs:"C:\Sentinel\buildtest.ps1" -filter:"+[*]Sentinel.* -[Fake*]* -[Fluent*]*" -mergebyhash -skipautoprops -hideskipped:All -coverbytest:* -excludebyattribute:*.Exclude*

The buildtest.ps1 contains: dotnet build dotnet vstest (Get-ChildItem -recurse -File *.Tests.*dll | ? { $_.FullName -notmatch "\\obj\\?" })

Output XML attached as well: opencover.zip

Method is: Sentinel.Registration.API\Sentinel.Registration\Sentinel.Registration.Api\Controllers\RegistrantController.cs:Get (as the example shown here)

If I don't use the exclude attribute, then line 44 in the image attachment is shown uncovered as well. This is considered a pass through method for us and we are saying it doesn't need unit test coverage (because the getRegistrantById class has it's own tests).

Here's an additional screenshot showing the Exclude attribute working for the constructor. You can see three methods here. Two with the Exclude attribute and one without. It correctly excludes the constructor. Is this an issue with delegates in a method?

excludebyattribute

How can we truly skip this method (and others like it)? In the output XML, I don't see any of the skippeddueto=Attribute things that would indicate that the method should be skipped.

I have reproduced this on the latest release (4.6.519) and the latest build (4.6.801).

Any ideas? Am I missing something?

dwkane avatar Dec 04 '17 17:12 dwkane

@sawilde Just checking in on this issue. Could you help with why the method isn't being skipped properly?

dwkane avatar Dec 11 '17 17:12 dwkane

Hi @dwkane - from your description, it is possibly due to it being an async method.

sawilde avatar Dec 11 '17 19:12 sawilde

@sawilde Yes, after a bit of searching existing issues, I would guess it is related to the async. This would be great to be unblocked on as I am looking to reduce the amount of noise in the reports for methods that don't need coverage. Thanks. :)

dwkane avatar Dec 11 '17 19:12 dwkane

@dwkane I'll have a look but having issue with my build server at the moment :(

sawilde avatar Dec 11 '17 23:12 sawilde

@sawilde Just one more screenshot showing awaits being indicated as uncovered branches. It might be related to my issue.

opencover2

dwkane avatar Dec 14 '17 18:12 dwkane

@dwkane OpenCover looks at IL branches and does its best to align them with source code - async/await may look simple to write but the IL produced it quite complex. If you want to diagnose it then you should start decompiling into IL and see if you can see the cause yourself.

sawilde avatar Dec 14 '17 22:12 sawilde

The await section in this code will be in a generated inner class called <Get>d__# where # is a numeral.

In general C# helper types generated from code in namespace.class.method will be types namespace.class/<method>xxx for some decorator xxx; or are in class namespace.class/<>xxx with the logic in a method called <method>xxx (lambdas take the latter shape). (F# is a different matter with generated types being inner types of the surrounding type but with a class name containing @<line number> rather than a direct indication of the enclosing function).

In any case, neither inherit the attributes on the lexically containing method, so it becomes a matter of IL navigation to go from the name to the enclosing method.

The uncovered branches in are implementation detail and reflect parts of a state machine in synthetic methods <ExecuteAsync>d__#.MoveNext() and <Action>d__#.MoveNext() -- there's a different path taken if the wait completes promptly (it does a synchronous return) than in the case where it does not (and it has to defer completion to a continuation); this is the sort of thing that will be difficult to force tests to exercise.

SteveGilham avatar May 02 '18 20:05 SteveGilham

Doing some more testing in this area, I have the following cases where the attribute on the function isn't propagated to all the syntactic scope of the function body C# 779a F# 779b

SteveGilham avatar May 04 '18 07:05 SteveGilham

It should also come as no surprise that C#7.0 local functions are similarly not excluded even if the enclosing method is.

SteveGilham avatar May 04 '18 21:05 SteveGilham

I just stumbled upon this issue as well:

coverage_bug

For me it seems to be that lambdas that cause the problem. I hope it helps.

arphox avatar May 29 '19 19:05 arphox

Yup - it is slated for a future release

sawilde avatar May 29 '19 23:05 sawilde