Code Coverage, yazılmış olan testin kodunuzun ne kadarını kapsadığını belirten bir ölçümdür. Bu ölçüm sayesinde kodunuzda testi yazılmamış kısımlar bulunuyorsa analizini yaparak ilgili satırların veya bölümlerinin testini yazmaya karar verebilirsiniz. Mümkün olduğunca code coverage yüzdesinin yüksek olmasına önem verilmelidir.

.NET Core'da dahili olarak code coverage raporunu oluşturabilecek bir araç bulunmamaktadır. Code coverage raporunu oluşturabilmek için Coverlet isimli kütüphaneden yararlanacağız.

Örnek projemizi yapmaya başlayabiliriz. Aşağıdaki komutları terminalimize yazarak sırasıyla solution, console ve test projelerimizi oluşturuyoruz.

$ dotnet new sln -o netcore-codecoverage-sample -n NetCore.CodeCoverage.Sample
$ cd netcore-codecoverage-sample
$ dotnet new console -o netcore-codecoverage-sample-console -n NetCore.CodeCoverage.Sample.Console
$ dotnet new xunit -o netcore-codecoverage-sample-console-tests -n NetCore.CodeCoverage.Sample.Console.Tests
$ dotnet sln ./NetCore.CodeCoverage.Sample.sln add netcore-codecoverage-sample-console/NetCore.CodeCoverage.Sample.Console.csproj
$ dotnet sln ./NetCore.CodeCoverage.Sample.sln add netcore-codecoverage-sample-console-tests/NetCore.CodeCoverage.Sample.Console.Tests.csproj
$ dotnet add netcore-codecoverage-sample-console-tests/NetCore.CodeCoverage.Sample.Console.Tests.csproj reference netcore-codecoverage-sample-console/NetCore.CodeCoverage.Sample.Console.csproj

Komutları yazdıktan sonra projemizi kullanmış olduğumuz IDE veya metin editörü ile açalım. Aşağıdaki ekran görüntüsündeki gibi bir proje yapımızın olması gerekmektedir.

code-coverage-1

Şimdi testimizi yazacağımız sınıfı yazmaya bağlayabiliriz. Console projemize Calculator isminde bir sınıf ekleyelim ve içeriğini aşağıdaki şekilde değiştirelim.

using System;

namespace netcore_codecoverage_sample_console
{
	public class Calculator
	{
		public double Sum(double a, double b)
		{
			return a + b;
		}

		public double Substract(double a, double b)
		{
			return a - b;
		}

		public double Multiply(double a, double b)
		{
			return a * b;
		}

		public double Divide(double a, double b)
		{
			if (b == 0)
			{
				throw new DivideByZeroException();
			}

			return a / b;
		}
	}
}

Yazmış olduğumuz sınıf basit bir şekilde toplama, çıkarma, çarpma ve bölme işlemlerini gerçekleştiren 4 metoda sahip.

Şimdi sırada bu sınıfa ait testimizi yazalım. Test projemiz altında bulunan UnitTest1.cs dosyamızın ismini CalculatorTests.cs olarak değiştirelim ve içeriği aşağıdaki şekilde düzenleyelim.

using netcore_codecoverage_sample_console;
using Xunit;

namespace NetCore.CodeCoverage.Sample.Console.Tests
{
	public class CalculatorTests
	{
		[Theory]
		[InlineData(1, 2, 3)]
		[InlineData(3, 2, 5)]
		[InlineData(100, 43, 143)]
		[InlineData(-43, 65, 22)]
		[InlineData(-431, 76, -355)]
		public void Sum_SumTwoNumbers_SumSuccess(double firstNumber, double secondNumber, double exceptedResult)
		{
			var calculator = new Calculator();
			var result = calculator.Sum(firstNumber, secondNumber);

			Assert.Equal(exceptedResult, result);
		}

		[Theory]
		[InlineData(1, 2, -1)]
		[InlineData(3, 2, 1)]
		[InlineData(100, 43, 57)]
		[InlineData(-43, 65, -108)]
		[InlineData(431, 76, 355)]
		public void Substract_SubstractTwoNumbers_SubstractSuccess(double firstNumber, double secondNumber, double exceptedResult)
		{
			var calculator = new Calculator();
			var result = calculator.Substract(firstNumber, secondNumber);

			Assert.Equal(exceptedResult, result);
		}

		[Theory]
		[InlineData(1, 2, 2)]
		[InlineData(3, 2, 6)]
		[InlineData(100, 43, 4300)]
		[InlineData(-43, 65, -2795)]
		[InlineData(431, 76, 32756)]
		public void Multiply_MultiplyTwoNumbers_MultiplySuccess(double firstNumber, double secondNumber, double exceptedResult)
		{
			var calculator = new Calculator();
			var result = calculator.Multiply(firstNumber, secondNumber);

			Assert.Equal(exceptedResult, result);
		}

		[Theory]
		[InlineData(1, 2, 0.5)]
		[InlineData(3, 2, 1.5)]
		[InlineData(200, 5, 40)]
		[InlineData(-60, 3, -20)]
		public void Divide_DivideTwoNumbers_DivideSuccess(double firstNumber, double secondNumber, double exceptedResult)
		{
			var calculator = new Calculator();
			var result = calculator.Divide(firstNumber, secondNumber);

			Assert.Equal(exceptedResult, result);
		}
	}
}

Yukarıdaki sınıfta Calculator sınıfına ait 4 metodun testini yazdık. Aşağıdaki komutu yazarak testlerimizin çalışıp çalışmadığını kontrol edelim.

dotnet test

code-coverage-2

Görüldüğü üzere testlerimiz başarıyla çalıştı. Şimdi sırada yazdığımız testin kodumuzun ne kadarını kapsadığının raporu çıkarmaya geldi.

Raporu oluşturabilmek için Coverlet'ın paketini test projemize eklemimiz gerekmektedir. Paketi ekleyebilmek için aşağıdaki komutu terminalimizde çalıştırıyoruz.

$ cd netcore-codecoverage-sample-console-tests/
$ dotnet add package coverlet.msbuild

Paket ekleme işlemlerini hallettikten sonra sadece testimizi çalıştırıp code coverage raporuna ulaşmak kaldı. İlgili rapora ulaşmak için aşağıdaki komutu terminalde çalıştırmamız yeterlidir.

$ dotnet test /p:CollectCoverage=true

code-coverage-4

Komutu çalıştırdıktan sonra yukarıdaki gibi bir ekranla karşılaşağız. Bu raporda testimizin kodumuzun %76.47'sinin kapsadığını görebilmekteyiz. Aynı zamanda test projemizin ana dizininde coverage.json isminde bir dosya oluşmaktadır. Bu dosyanın içerisinde de raporla ilgili bilgiler bulunmaktadır.

code-coverage-5

Peki code coverage raporlarımızı SonarQube gibi kod analizi araçlarının anlayacağı şekilde nasıl oluşturabiliriz? Bunun cevabı ise LCOV dosya formatında yatmakta. SonarQube LCOV dosya yapısındaki raporları analiz edebilektedir. Coverlet kütüphanesi ise LCOV formatında rapor çıktısı verebilmektedir. LCOV formatında rapor alabilmek için aşağıdaki komutu çalıştırmamız yeterlidir.

$ dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=./lcov

code-coverage-6

Yukarıda da gördüğünüz gibi test projemizin ana dizininde lcov.info isminde bir dosya oluştu. Bu dosyayı SonarQube'e analiz aşamasında verdiğiniz takdirde code coverage bilgileriniz SonarQube üzerinde gözükecektir.

Örnek uygulamaya ait kaynak kodlara https://github.com/mennan/netcore-codecoverage-sample adresinden ulaşabilirsiniz.