1

我在 SonarQube 5.3 中发现了一个场景,其中在 Visual Studio 代码覆盖分析的代码覆盖中报告了不同的值。

这是一个使用 MSTest 框架的小型复制品。

我无法确定我们正在做的事情是否有问题,或者其中一个应用程序是否有问题。

被测对象

[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();
    }
}

该代码具有以下测试:

[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 将百分比显示为:90.10%

SonarQube 显示百分比为:40.00%


Sonar 似乎没有考虑在

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

方法:public bool Equals(Document other)

我已经调试了测试以验证线路是否被击中。

4

2 回答 2

0

实际上可能就像其他人说你必须在调试模式下构建。但是我的同事发现了一件奇怪的事情:

如果将 () 添加到[TestClass][TestMethod]装饰器中 [TestClass()][TestMethod()]它可以正常工作。

问题是告诉所有开发人员 Sonar 需要它,而 Microsoft 文档则不需要。

这适用于 Sonarqube DE。在社区版中工作正常,没有 ()

于 2020-04-15T21:14:33.517 回答
0

可能是行/分支覆盖率之间的差异: 声纳中代码覆盖率和行覆盖率之间的区别是什么

...或白色间距/换行。

您可以在此处找到 SonarQube 指标描述页面的公式:http: //docs.sonarqube.org/display/SONAR/Metric+definitions#Metricdefinitions-Tests

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

在哪里

CT - 至少一次评估为“真”的分支 CF - 至少一次评估为“假”的分支 LC - 覆盖的行 (lines_to_cover - unlocked_lines)

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

于 2016-07-13T21:08:19.767 回答