在sonarqube .NET代码覆盖率的差异

编程入门 行业动态 更新时间:2024-10-12 10:27:14
本文介绍了在sonarqube .NET代码覆盖率的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我发现SonarQube 5.3这样一个场景,被报道从Visual Studio代码覆盖分析代码覆盖不同的值。

下面是一个小的复制,使用的MSTest框架。

我无法确定,如果有什么错的,我们在做什么,或者如果一个应用程序是错误的。

待测物

[Serializable接口] 公共类文档:IEquatable<文件> ; {众长标识{搞定;组; } 公共字符串名称{;组; } 众长DocumentHandle {搞定;组; } 众长BatchId {搞定;组; } 公共字符串BatchName {搞定;组; } 公共字符串RepositoryName {搞定;组; } 众长DocumentTypeId {搞定;组; } 公共字符串DocumentTypeName {搞定;组; } 公众诠释的SequenceNumber {搞定;组; } 公共字符串LoanNumber {搞定;组; } 公共BOOL IsJunked {搞定;组; } 公众的DateTime ArrivalDate {搞定;组; } 公共布尔等于(其他文件) {如果(的ReferenceEquals(其他,NULL)) {返回FALSE; } 如果(ID = other.Id!) {返回FALSE; } 如果 {返回假(string.Equals(名称,other.Name)!); } 如果(DocumentHandle = other.DocumentHandle!) {返回FALSE; } 如果(BatchId = other.BatchId!) {返回FALSE; } 如果 {返回假(string.Equals(BatchName,other.BatchName)!); } 如果 {返回假(string.Equals(RepositoryName,other.RepositoryName)!); } 如果(DocumentTypeId = other.DocumentTypeId!) {返回false; } 如果 {返回假(string.Equals(DocumentTypeName,other.DocumentTypeName)!); } 如果(的SequenceNumber = other.SequenceNumber!) {返回FALSE; } 如果 {返回假(string.Equals(LoanNumber,other.LoanNumber)!); } 如果(IsJunked = other.IsJunked!) {返回false; } 如果(ArrivalDate = other.ArrivalDate!) {返回false; } 返回真; } 公众覆盖布尔等于(obj对象) {如果(的ReferenceEquals(NULL,OBJ)) {返回假; } 如果(的ReferenceEquals(这一点,OBJ)) {返回真; } 返回等于((文件)目标文件); } 公共静态布尔运算符==(文档文档1,文档文件2) {返回的ReferenceEquals(文档1,NULL)?的ReferenceEquals(文件2,空):document1.Equals(文件2); } 公共静态布尔运算符=(文档文档1,文档文件2) {返回(文档1 ==文件2);! } 公共覆盖INT的GetHashCode() { //禁用ReSharper的一次BaseObjectGetHashCodeCallInGetHashCode //这样做是为了抑制约需要的信息重写GetHashCode //因为这个类没有只读属性没有办法提供更好的哈希码返回base.GetHashCode(); } }

该码具有以下测试:

[TestClass中] [ExcludeFromCodeCoverage] 公共类DocumentTests {私人文件defaultDocument; 私人文件alteredDocument; [TestInitialize] 公共无效设置() { defaultDocument =新文件 { ID = 1, NAME =Growlithe, DocumentHandle = 2, BatchId = 3, BatchName =六尾, RepositoryName =Pancham, DocumentTypeId = 4, DocumentTypeName =Skrelp,的SequenceNumber = 5, LoanNumber =Zorua, IsJunked =真, ArrivalDate =新日期时间(1,1,1 )}; alteredDocument =新文件 { ID = 1, NAME =Growlithe, DocumentHandle = 2, BatchId = 3 , BatchName =六尾, RepositoryName =Pancham, DocumentTypeId = 4, DocumentTypeName =Skrelp,的SequenceNumber = 5, LoanNumber =Zorua, IsJunked = TRUE, ArrivalDate =新日期时间(1,1,1)}; } [TestMethod的] 公共无效ToStringMethod_DocumentPOCO_ConvertObjectToString() { //安排 VAR expectedStringDocument =文档+环境。 NEWLINE + \tId:101+ Environment.NewLine + \tName:测试名+ Environment.NewLine + \tDocumentHandle:500万支+ Environment.NewLine + \tBatchId:5亿+ Environment.NewLine + \tBatchName:TestBatchName+ Environment.NewLine + \tRepositoryName:TestRepositoryName+ Environment.NewLine + \tDocumentTypeId:500万支+ Environment.NewLine + \tDocumentTypeName:TestDocumentTypeName+ Environment.NewLine + \tSequenceNumber:101+ Environment.NewLine + \tLoanNumber:TestLoanNumber+ Environment.NewLine + \tIsJunked:假+ Environment.NewLine + \tArrivalDate:+ DateTime.Now + Environment.NewLine; alteredDocument =新文件 { n = 101, NAME =测试名, DocumentHandle = 5000000 BatchId = 5亿, BatchName =TestBatchName, RepositoryName =TestRepositoryName, DocumentTypeId = 5000000 DocumentTypeName =TestDocumentTypeName,的SequenceNumber = 101, LoanNumber =TestLoanNumber, IsJunked =假, ArrivalDate = DateTime.Now }; //法案 VAR processedDocumentObj = StringUtility.StringUtility.ConvertToString(alteredDocument); //断言 Assert.IsTrue(processedDocumentObj.Equals(expectedStringDocument)); } [TestMethod的] 公共无效EqualsReturnsTrueForEquivalentDocument() { Assert.IsTrue(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForNullDocument() { alteredDocument = NULL; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentId() { alteredDocument.Id = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentName() { alteredDocument.Name =Arcanine; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentDocumentHandle() { alteredDocument.DocumentHandle = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentBatchId() { alteredDocument.BatchId = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentBatchName() { alteredDocument.BatchName =Ninetails; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentRepositoryName() { alteredDocument.RepositoryName =Pangoro; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentDocumentTypeId() { alteredDocument.DocumentTypeId = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentDocumentTypeName() { alteredDocument.DocumentTypeName =Dragalge; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentSequenceNumber() { alteredDocument.SequenceNumber = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentLoanNumber() { alteredDocument.LoanNumber =Zoroark; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentIsJunked() { alteredDocument.IsJunked = FALSE; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsReturnsFalseForDifferentArrivalDate() { alteredDocument.ArrivalDate =新日期时间(2,2,2); Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod的] 公共无效EqualsOperatorWorksForNonNullValues() { Assert.IsTrue(defaultDocument == alteredDocument); } [TestMethod的] 公共无效NotEqualsOperatorWorksForNonNullValues() { alteredDocument = NULL; Assert.IsTrue(!defaultDocument = alteredDocument); } [TestMethod的] 公共无效EqualsOperatorReturnsFalseForNullDotNonNull() { alteredDocument = NULL; Assert.IsFalse(alteredDocument == defaultDocument); } [TestMethod的] 公共无效EqualsOperatorReturnsFalseForNonNullDotNull() { alteredDocument = NULL; Assert.IsFalse(defaultDocument == alteredDocument); } [TestMethod的] 公共无效EqualsOperatorReturnsTrueForNullDotNull() { alteredDocument = NULL; defaultDocument = NULL; Assert.IsTrue(defaultDocument == alteredDocument); } }

Visual Studio的显示比例为:90.10%

SonarQube显示比例为:40.00%

声纳似乎没有考虑

术后早期return语句

如果(的ReferenceEquals(其他,NULL)) {返回FALSE; }

方法:公共布尔等于(其他文件)

我调试的测试,以验证线被击中。

解决方案

这可能是行/分支覆盖之间的差异:的什么是声纳

代码覆盖率和覆盖线之间的区别

.. 。或白色间距/换行

您可以找到SonarQube的度量这里介绍页面公式:的 docs.sonarqube/display/SONAR/Metric+definitions#Metricdefinitions-Tests

覆盖率=(CT + CF + LC)/(2 * b + EL)

其中,

$该评估为假至少一次 LC分支 - - 线覆盖(lines_to_cover - uncovered_lines),该评价为真至少一次的CF的分支 -

CT >

b - 分支总数(2 * b = conditions_to_cover) EL - 可执行行总数(lines_to_cover)

I found a scenario with SonarQube 5.3 where different values are being reported in code coverage from Visual Studio code coverage analysis.

Here is a small reproduction, using the MSTest framework.

I'm not able to determine if there is something wrong in what we are doing or if one of the applications is wrong.

The object being tested

[Serializable] public class Document : IEquatable<Document> { public long Id { get; set; } public string Name { get; set; } public long DocumentHandle { get; set; } public long BatchId { get; set; } public string BatchName { get; set; } public string RepositoryName { get; set; } public long DocumentTypeId { get; set; } public string DocumentTypeName { get; set; } public int SequenceNumber { get; set; } public string LoanNumber { get; set; } public bool IsJunked { get; set; } public DateTime ArrivalDate { get; set; } public bool Equals(Document other) { if (ReferenceEquals(other, null)) { return false; } if (Id != other.Id) { return false; } if (!string.Equals(Name, other.Name)) { return false; } if (DocumentHandle != other.DocumentHandle) { return false; } if (BatchId != other.BatchId) { return false; } if (!string.Equals(BatchName, other.BatchName)) { return false; } if (!string.Equals(RepositoryName, other.RepositoryName)) { return false; } if (DocumentTypeId != other.DocumentTypeId) { return false; } if (!string.Equals(DocumentTypeName, other.DocumentTypeName)) { return false; } if (SequenceNumber != other.SequenceNumber) { return false; } if (!string.Equals(LoanNumber, other.LoanNumber)) { return false; } if (IsJunked != other.IsJunked) { return false; } if (ArrivalDate != other.ArrivalDate) { return false; } return true; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) { return false; } if (ReferenceEquals(this, obj)) { return true; } return Equals((Document) obj); } public static bool operator == (Document document1, Document document2) { return ReferenceEquals(document1, null) ? ReferenceEquals(document2, null) : document1.Equals(document2); } public static bool operator != (Document document1, Document document2) { return !(document1 == document2); } public override int GetHashCode() { // ReSharper disable once BaseObjectGetHashCodeCallInGetHashCode // This was done to suppress the messages about needing to override GetHashCode // Because this class has no ReadOnly properties there is no way to provide a better hashcode return base.GetHashCode(); } }

The code has the following tests:

[TestClass] [ExcludeFromCodeCoverage] public class DocumentTests { private Document defaultDocument; private Document alteredDocument; [TestInitialize] public void Setup() { defaultDocument = new Document { Id = 1, Name = "Growlithe", DocumentHandle = 2, BatchId = 3, BatchName = "Vulpix", RepositoryName = "Pancham", DocumentTypeId = 4, DocumentTypeName = "Skrelp", SequenceNumber = 5, LoanNumber = "Zorua", IsJunked = true, ArrivalDate = new DateTime(1, 1, 1) }; alteredDocument = new Document { Id = 1, Name = "Growlithe", DocumentHandle = 2, BatchId = 3, BatchName = "Vulpix", RepositoryName = "Pancham", DocumentTypeId = 4, DocumentTypeName = "Skrelp", SequenceNumber = 5, LoanNumber = "Zorua", IsJunked = true, ArrivalDate = new DateTime(1, 1, 1) }; } [TestMethod] public void ToStringMethod_DocumentPOCO_ConvertObjectToString() { // Arrange var expectedStringDocument = "Document" + Environment.NewLine + "\tId: 101" + Environment.NewLine + "\tName: TestName" + Environment.NewLine + "\tDocumentHandle: 5000000" + Environment.NewLine + "\tBatchId: 500000000" + Environment.NewLine + "\tBatchName: TestBatchName" + Environment.NewLine + "\tRepositoryName: TestRepositoryName" + Environment.NewLine + "\tDocumentTypeId: 5000000" + Environment.NewLine + "\tDocumentTypeName: TestDocumentTypeName" + Environment.NewLine + "\tSequenceNumber: 101" + Environment.NewLine + "\tLoanNumber: TestLoanNumber" + Environment.NewLine + "\tIsJunked: False" + Environment.NewLine + "\tArrivalDate: " + DateTime.Now + Environment.NewLine; alteredDocument = new Document { Id = 101, Name = "TestName", DocumentHandle = 5000000, BatchId = 500000000, BatchName = "TestBatchName", RepositoryName = "TestRepositoryName", DocumentTypeId = 5000000, DocumentTypeName = "TestDocumentTypeName", SequenceNumber = 101, LoanNumber = "TestLoanNumber", IsJunked = false, ArrivalDate = DateTime.Now }; // Act var processedDocumentObj = StringUtility.StringUtility.ConvertToString(alteredDocument); // Assert Assert.IsTrue(processedDocumentObj.Equals(expectedStringDocument)); } [TestMethod] public void EqualsReturnsTrueForEquivalentDocument() { Assert.IsTrue(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForNullDocument() { alteredDocument = null; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentId() { alteredDocument.Id = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentName() { alteredDocument.Name = "Arcanine"; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentDocumentHandle() { alteredDocument.DocumentHandle = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentBatchId() { alteredDocument.BatchId = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentBatchName() { alteredDocument.BatchName = "Ninetails"; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentRepositoryName() { alteredDocument.RepositoryName = "Pangoro"; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentDocumentTypeId() { alteredDocument.DocumentTypeId = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentDocumentTypeName() { alteredDocument.DocumentTypeName = "Dragalge"; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentSequenceNumber() { alteredDocument.SequenceNumber = 9; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentLoanNumber() { alteredDocument.LoanNumber = "Zoroark"; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentIsJunked() { alteredDocument.IsJunked = false; Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsReturnsFalseForDifferentArrivalDate() { alteredDocument.ArrivalDate = new DateTime(2, 2, 2); Assert.IsFalse(defaultDocument.Equals(alteredDocument)); } [TestMethod] public void EqualsOperatorWorksForNonNullValues() { Assert.IsTrue(defaultDocument == alteredDocument); } [TestMethod] public void NotEqualsOperatorWorksForNonNullValues() { alteredDocument = null; Assert.IsTrue(defaultDocument != alteredDocument); } [TestMethod] public void EqualsOperatorReturnsFalseForNullDotNonNull() { alteredDocument = null; Assert.IsFalse(alteredDocument == defaultDocument); } [TestMethod] public void EqualsOperatorReturnsFalseForNonNullDotNull() { alteredDocument = null; Assert.IsFalse(defaultDocument == alteredDocument); } [TestMethod] public void EqualsOperatorReturnsTrueForNullDotNull() { alteredDocument = null; defaultDocument = null; Assert.IsTrue(defaultDocument == alteredDocument); } }

Visual Studio shows the percentage as: 90.10%

SonarQube shows the percentage as: 40.00%

Sonar doesn't appear to consider the early return statements after the

if (ReferenceEquals(other, null)) { return false; }

of the method: public bool Equals(Document other)

I have debugged the tests to validate the lines are hit.

解决方案

It may be a difference between line/branch coverage: What is the difference between code coverage and line coverage in sonar

... or white spacing/line wrapping.

You can find the formula for SonarQube's metric description page here: docs.sonarqube/display/SONAR/Metric+definitions#Metricdefinitions-Tests

coverage = (CT + CF + LC)/(2*B + EL)

where

CT - branches that evaluated to "true" at least once CF - branches that evaluated to "false" at least once LC - lines covered (lines_to_cover - uncovered_lines)

B - total number of branches (2*B = conditions_to_cover) EL - total number of executable lines (lines_to_cover)

更多推荐

在sonarqube .NET代码覆盖率的差异

本文发布于:2023-11-14 22:09:54,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1588627.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:覆盖率   差异   代码   sonarqube   NET

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!