Birim testleri yazmanın bir dizi 'AssertEquals'tan daha iyi bir yolu var mı?


12

Qunit kullanarak birim testimin ne olması gerektiğine dair temel bir örnek:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>

<link rel="stylesheet" href="qunit/qunit-1.13.0.css">
<script src = "qunit/qunit-1.13.0.js"></script>
<script src = "../js/fuzzQuery.js"></script>

<script>

test("Fuzz Query Basics", function()
        {
            equal(fuzzQuery("name:(John Smith)"), "name:(John~ Smith~)");
            equal(fuzzQuery("name:Jon~0.1"), "name:Jon~0.1");
            equal(fuzzQuery("Jon"), "Jon~");
            //etc

        }
    );

</script>
</head>
<body>
    <div id="qunit"></div>
</body>
</html>

Şimdi bunun biraz tekrarlı olduğunu düşünüyordum.

Tüm girişleri / çıkışları bir diziye koyabilir ve onu bir döngüye sokabilir.

test("Fuzz Query Basics", function()
        {
            var equals = [
                           ["name:(John Smith)", "name:(John~ Smith~)"],
                           ["name:Jon~0.1", "name:Jon~0.1"],
                           ["Jon", "Jon~"]
                           ];

            for (var i = 0; i<equals.length; i++)
                {
                    equal(fuzzQuery(equals[i][0]), equals[i][1]);               
                }

        }
    );

Ve bu iyi çalışıyor.

Bu ikinci yöntem için düşünebileceğim tek avantaj, eğer gerçekten kullanmak istemediğiniz ortaya çıkarsa equal, bu değişikliği tek bir noktada yapmak daha kolay.

Okunabilirlik açısından, her ikisinin de kesin olduğunu düşünmüyorum, ancak muhtemelen ikincisini tercih ediyorum.

Daha da soyutlayarak, giriş / çıkış vakalarını değiştirmeyi kolaylaştırabilecek ayrı bir CSV dosyasına koyabilirsiniz.

Soru şu - bu tür birim testleri yazmayla ilgili genel sözleşmeler nelerdir?

Bunları dizilere yerleştirmemeniz için bir neden var mı?


Bunlardan biri size hangi değerin başarısız olduğunu söyleyecek mi?
JeffO

1
@JeffO - Evet - QUnit ile - Bir test başarısız olursa, çıktı beklenen değeri ve gerçek değeri gösterir.
dwjohnston

Yanıtlar:


8

Yeniden düzenlenmiş testlerinizin bir kokusu var: Koşullu Test Mantığı .

Testlerinize koşullu mantık yazmaktan kaçınmanızın nedenleri iki yönlüdür. Birincisi, bağlı xUnit Patterns makalesinde açıklandığı gibi test kodunuzun doğru olduğundan emin olmanızı engellemektir.

İkincisi, testlerin anlamını gizlemesidir. Test Yöntemleri yazıyoruz çünkü belirli bir davranışı test etmek için mantığı tek bir yere koyuyorlar ve açıklayıcı bir isim vermemize izin veriyorlar ( testler için iyi isimlerin değerinin araştırılması için Dan North'un orijinal BDD makalesine bakın ). Testleriniz bir fordöngü ile tek bir fonksiyonun içine gizlendiğinde , okuyucu için kodun anlamını gizler. Okuyucu sadece döngüyü kavramakla kalmaz, aynı zamanda döngü içinde test edilen tüm farklı davranışları zihinsel olarak çözmelidir.

Çözüm, her zaman olduğu gibi, bir soyutlama seviyesine çıkmaktır. XUnit.NET veya Contexts gibi parametreli testler veren bir test çerçevesi kullanın (sorumluluk reddi: Contexts yazdım). Bu, ayrı davranışlar için testleri ayrı tutarken aynı davranış için üçgenleme testlerini doğal bir şekilde gruplandırmanıza olanak tanır.


İyi soru, bu arada
Benjamin Hodgson

1
1) Bir soyutlama seviyesine yükselirseniz, for döngüsü tarafından gizlendiğini söylediğiniz aynı ayrıntıları gizlemiyor musunuz? 2) burada parametreli testlerin uygulanabileceğinden emin değilim. Burada bir yerlerde paralellikler var gibi görünüyor, ancak 10-20 değerlik bir veri setine sahip olduğum ve sadece hepsini SUT aracılığıyla çalıştırmak istediğim OP'lere benzer birçok durum yaşadım. Evet, her değer farklıdır ve potansiyel olarak farklı boudary'ları test eder, ancak aslında her bir değer için "icat" test isimleri aşırıya kaçar. Benzer kullanımda optimal değer / kod boyutu oranı buldum ...
DXM

... döngüler. Test başarısız olduğu sürece, iddia eden tam olarak başarısız olanı yazdırır, geliştirici sorunu tam olarak belirlemek için yeterli geri bildirime sahiptir.
DXM

@DXM 1) test çerçevesi parametreli test işlevselliği sağlar. Test çerçevesine dolaylı olarak güveniyoruz, bu nedenle testler yazmıyoruz. 2) parametrelenmiş testler tam olarak bu amaç içindir: her seferinde tam olarak aynı adımları gerçekleştiriyorsunuz, ancak farklı giriş / çıkış değerleri ile. Sınama çerçevesi, aynı sınama yöntemiyle farklı girdileri çalıştırarak her biri için ad yazma gereksinimini ortadan kaldırır.
Benjamin Hodgson

5

Gerçekten Veriye Dayalı Birim Testi istediğiniz gibi görünüyor. QUnit kullanarak bahsettiğinizden beri, parametreli testleri etkinleştiren bir eklenti buldum:

https://github.com/AStepaniuk/qunit-parameterize

Test kodunun kendisi koşullu olmadığı sürece veri odaklı bir testte ideolojik olarak yanlış bir şey yoktur. Test kodunuza bakıldığında, Veriye Dayalı Test için çok iyi bir aday gibi görünüyor.

GitHub README için örnek kod:

QUnit
    .cases([
        { a : 2, b : 2, expectedSum : 4 },
        { a : 5, b : 5, expectedSum : 10 },
        { a : 40, b : 2, expectedSum : 42 }
    ])
    .test("Sum test", function(params) {
        var actualSum = sum(params.a, params.b);
        equal(actualSum, params.expectedSum);
    });

1
Kabul edildi, veriye dayalı bir test gibi görünüyor. Ama ikinci kod örneğinde zaten olduğu gibi görünüyor.
Robert Harvey

1
@RobertHarvey - Doğru. Yapmaya çalıştığı şey için kabul edilen bir terim vardır ve bu tür testlerin yazılmasını kolaylaştırmak için kullanılan test çerçevesi için bir eklenti vardır. Gelecek için bir cevapta kayda değer olduğunu düşündüm, hepsi bu.
Greg Burghardt

1

Daha sürdürülebilir olan diziyi kullanarak kendinizi daha az tekrarlıyorsunuz. Kullanmayı sevdiğim bir yaklaşım, testleri düzenleyen, gerçekleştiren ve savunan ancak test ettiğim giriş parametrelerini kabul eden ayrı bir yönteme sahip olmaktır, bu nedenle her girdi seti için 1 test yöntemim vardır.

Bu, hangi test / girişlerin başarısız olduğunu anında söylememe izin veriyor.


0

İkinci yaklaşımınızı beğendim, ancak 2 Puan eklerim

  • dizinlerle çalışmak temiz bir yol olmadığından, test edilen verileri depolamak için diziler kullanmayın
  • fordöngüler kullanma

'

[
    {
        process: "name:(John Smith)",
        result: "name:(John~ Smith~)"
    },
    {
        process: "name:Jon~0.1", 
        result: "name:Jon~0.1"
    },
    {
        process: "Jon", 
        result: "Jon~"
    }
]
.forEach(function(data){

    var result = fuzzQuery(data.process);
    equal(result, data.result);
});

Qunit hakkında emin değilim, ancak iyi bir test koşucusu hangi giriş dizesinin başarısız olduğunu ve beklenen sonucun ne olduğunu gösterecektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.