Mutasyon testi

Mutasyon testi, birim testlerimizin kalitesini değerlendirmenin bir yoludur. Mutasyon testi için Stryker.NET aracı kodunuzda mutasyonları otomatik olarak gerçekleştirir, testler çalıştırır ve sonuçları içeren ayrıntılı bir rapor oluşturur.

Örnek test senaryosu

İndirimi dikkate alarak fiyatı hesaplayan bir yöntemine sahip örnek bir Calculate sınıfını göz önünde bulundurun.

public class PriceCalculator
{
    public decimal CalculatePrice(decimal price, decimal discountPercent)
    {
        if (price <= 0)
        {
            throw new ArgumentException("Price must be greater than zero.");
        }

        if (discountPercent < 0 || discountPercent > 100)
        {
            throw new ArgumentException("Discount percent must be between 0 and 100.");
        }

        var discount = price * (discountPercent / 100);
        var discountedPrice = price - discount;

        return Math.Round(discountedPrice, 2);
    }
}

Yukarıdaki yöntem aşağıdaki birim testleri kapsamındadır:

[Fact]
public void ApplyDiscountCorrectly()
{
    decimal price = 100;
    decimal discountPercent = 10;

    var calculator = new PriceCalculator();

    var result = calculator.CalculatePrice(price, discountPercent);

    Assert.Equal(90.00m, result);
}

[Fact]
public void InvalidDiscountPercent_ShouldThrowException()
{
    var calculator = new PriceCalculator();

    Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, -1));
    Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, 101));
}

[Fact]
public void InvalidPrice_ShouldThrowException()
{
    var calculator = new PriceCalculator();

    Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(-10, 10));
}

Yukarıdaki kod, biri PriceCalculator gibi davranan hizmet için diğeri test projesi olan iki projeyi vurgular.

Genel aracı yükleme

İlk olarak Stryker.NETyükleyin. Bunu yapmak için komutunu yürütmeniz gerekir:

dotnet tool install -g dotnet-stryker

strykerçalıştırmak için, birim testi projesinin bulunduğu dizindeki komut satırından çağırın:

dotnet stryker

Testler çalıştırıldıktan sonra konsolda bir rapor görüntülenir.

Stryker konsol raporu

Stryker.NET ayrıntılı bir HTML raporunu StrykerOutput dizinine kaydeder.

Stryker ilk raporu

Şimdi, mutantların ne olduğunu ve 'hayatta kalma' ve 'öldürülme'nin ne demek olduğunu düşünün. Mutant, kodunuzda Stryker'ın bilerek yaptığı küçük bir değişikliktir. Bu basit bir fikirdir: Testleriniz iyiyse, değişikliği yakalamalı ve başarısız olmalıdır. Yine de geçerlerse, testleriniz yeterince güçlü olmayabilir.

Örneğimizde, bir mutant price <= 0ifadesinin yerini alacak, örneğin, price < 0ile, birim testleri çalıştırıldıktan sonra.

Stryker çeşitli mutasyon türlerini destekler:

Türü Açıklama
Eşdeğer Eşdeğer işleç, bir işleci eşdeğeriyle değiştirmek için kullanılır. Örneğin, x < yx <= yolur.
Aritmetik Aritmetik işleci, bir aritmetik işleci eşdeğeriyle değiştirmek için kullanılır. Örneğin, x + yx - yolur.
Dize Dize işleci, bir dizeyi eşdeğeriyle değiştirmek için kullanılır. Örneğin, "text"""olur.
Mantıklı Mantıksal işleç, bir mantıksal işleci eşdeğeriyle değiştirmek için kullanılır. Örneğin, x && yx \|\| yolur.

Ek mutasyon türleri için Stryker.NET: Mutasyonlar belgelerine bakın.

Mutasyon testi sonuçlarını yorumlama

Stryker.NET çalıştırdıktan sonra, mutantları öldürülmüş, hayatta kalmış veya zaman aşımı olarak kategorilere ayıran bir rapor alırsınız. Bu sonuçları şu şekilde yorumlayıp üzerinde işlem yapabilirsiniz:

  • Öldürüldü: Bunlar, testlerinizin başarıyla yakalandığı değişikliklerdir. Çok sayıda öldürülmüş mutant test paketinizin mantık hatalarını etkili bir şekilde algıladığını gösteriyor.
  • Hayatta kaldı: Bu değişiklikler testlerinize yakalanmadı. Test kapsamındaki boşlukları veya çok zayıf onayları belirlemek için bunları gözden geçirin. Mutant gerçek olsaydı başarısız olacak hedefli birim testleri eklemeye odaklanın.
  • Zaman aşımı: Bu mutasyonlar kodunuzun kilitlenmesine veya izin verilen süreyi aşmasına neden oldu. Bu, sonsuz döngülerle veya iyileştirilmemiş yollarla gerçekleşebilir. Kod mantığını araştırın veya gerekirse zaman aşımı eşiğini artırın.

Uyarı

100% mutasyon skorunu takip etme. Bunun yerine, algılanmayan hataların en yüksek maliyetli olduğu yüksek risk veya iş açısından kritik alanlara odaklanın.

CI/CD iş akışınıza mutasyon testi ekleme

Mutasyon testini sürekli tümleştirme ve teslim iş akışlarınızla sorunsuz bir şekilde tümleştirebilirsiniz. Örneğin, Stryker.NET Azure Pipelines veya GitHub Actions kurulumunuz içinde çalışacak şekilde yapılandırılabilir ve otomatikleştirilmiş test sürecinizin bir parçası olarak kalite eşiklerini zorunlu kılmanıza olanak tanır.

Özelleştirme

Stryker.NET, işlem hattınızın eşiklerini ayarlamanın yanı sıra proje gereksinimlerinizin her biri için farklı yapılandırmalara sahip olma olanağı da sunar. stryker-config.json dosyasını kullanarak davranışı özelleştirebilirsiniz.

{
  "stryker-config": {
    "ignore-mutations": [
      "string",
      "logical"
    ],
    "ignore-methods": [
      "*Logs"
    ],
    "mutate": [
      "!**/Migrations/*",
      "!**/*.Designer.cs"
    ]
  }
}
  • ignore-mutasyonlar: Gürültülü veya uygulama mantığınızla ilgili olmadıkları için testten dışlanması gereken mutasyon türleri. Raporlarınızda olarak Ignoredgörünürler.
  • ignore-methods: İmzalarına göre tüm yöntemleri atlamak için bunu kullanabilirsiniz. Bunlar raporlarınızda Ignored şeklinde görünür. Önceki örnekte, "loglar" ile biten tüm yöntemler yoksayılır.
  • mutate: Bu seçenek olmadan, Stryker projenizdeki tüm dosyaları değiştirmeye çalışır. Bununla, dosyaları veya klasörlerin tamamını yoksayabilirsiniz. Yukarıdaki örnekte, Migrations klasörünün içindeki her şey ve .Designer.cs dosyalarının tümü (genellikle otomatik olarak üretilir) yoksayılır.

Daha fazla bilgi için bkz. Stryker: Yapılandırma.

Artımlı geliştirme

Kodunuzu değiştirdikten sonra birim testleri başarıyla geçerse, yeterince sağlam değillerdir ve mutasyon hayatta kalmıştır. Mutasyon testinden sonra beş mutant hayatta kalır.

Sınır değerleri için test verileri ekleyelim ve mutasyon testlerini yeniden çalıştıralım.

[Fact]
public void InvalidPrice_ShouldThrowException()
{
    var calculator = new PriceCalculator();

    // changed price from -10 to 0
    Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(0, 10));
}

[Fact] // Added test for 0 and 100 discount
public void NoExceptionForZeroAnd100Discount()
{
    var calculator = new PriceCalculator();

    var exceptionWhen0 = Record.Exception(() => calculator.CalculatePrice(100, 0));
    var exceptionWhen100 = Record.Exception(() => calculator.CalculatePrice(100, 100));

    Assert.Null(exceptionWhen0);
    Assert.Null(exceptionWhen100);
}

Stryker ikinci rapor

Gördüğünüz gibi, eşdeğer mutantları düzeltdikten sonra yalnızca dize mutasyonları kaldı ve özel durum iletisinin metnini kontrol ederek kolayca 'öldürebiliyoruz'.

[Fact]
public void InvalidDiscountPercent_ShouldThrowExceptionWithCorrectMessage()
{
    var calculator = new PriceCalculator();

    var ex1 = Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, -1));
    Assert.Equal("Discount percent must be between 0 and 100.", ex1.Message);

    var ex2 = Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(100, 101));
    Assert.Equal("Discount percent must be between 0 and 100.", ex2.Message);
}

[Fact]
public void InvalidPrice_ShouldThrowExceptionWithCorrectMessage()
{
    var calculator = new PriceCalculator();

    var ex = Assert.Throws<ArgumentException>(() => calculator.CalculatePrice(0, 10));
    Assert.Equal("Price must be greater than zero.", ex.Message);
}

Stryker son rapor

Mutasyon testi, testleri daha güvenilir hale getiren fırsatlar bulmaya yardımcı olur. Sizi yalnızca 'mutlu yol' değil, aynı zamanda karmaşık sınır durumlarını da denetlemeye zorlayarak üretimdeki hataların olasılığını azaltır.