Birim testleri için kodu tekrarlamak uygun mudur?


11

Bir sınıf ödevi için bazı sıralama algoritmaları yazdım ve algoritmaların doğru bir şekilde uygulandığından emin olmak için birkaç test yazdım. Testlerim sadece 10 satır uzunluğunda ve 3 tanesi var, ancak 3 arasında sadece 1 satır değiştiğinden, tekrarlanan kod çok fazla. Bu kodu daha sonra her testten çağrılan başka bir yönteme yeniden aktive etmek daha mı iyi? Daha sonra yeniden düzenlemeyi test etmek için başka bir test yazmam gerekmez mi? Değişkenlerin bazıları sınıf seviyesine kadar bile taşınabilir. Test sınıfları ve yöntemleri, normal sınıflar / yöntemlerle aynı kuralları izlemeli mi?

İşte bir örnek:

    [TestMethod]
    public void MergeSortAssertArrayIsSorted()
    {
        int[] a = new int[1000];
        Random rand = new Random(DateTime.Now.Millisecond);
        for(int i = 0; i < a.Length; i++)
        {
            a[i] = rand.Next(Int16.MaxValue);
        }
        int[] b = new int[1000];
        a.CopyTo(b, 0);
        List<int> temp = b.ToList();
        temp.Sort();
        b = temp.ToArray();

        MergeSort merge = new MergeSort();
        merge.mergeSort(a, 0, a.Length - 1);
        CollectionAssert.AreEqual(a, b);
    }
    [TestMethod]
    public void InsertionSortAssertArrayIsSorted()
    {
        int[] a = new int[1000];
        Random rand = new Random(DateTime.Now.Millisecond);
        for (int i = 0; i < a.Length; i++)
        {
            a[i] = rand.Next(Int16.MaxValue);
        }
        int[] b = new int[1000];
        a.CopyTo(b, 0);
        List<int> temp = b.ToList();
        temp.Sort();
        b = temp.ToArray();

        InsertionSort merge = new InsertionSort();
        merge.insertionSort(a);
        CollectionAssert.AreEqual(a, b); 
    }

Yanıtlar:


21

Test kodu hala koddur ve sürdürülmesi gerekir.

Kopyalanan mantığı değiştirmeniz gerekirse, normal olarak kopyaladığınız her yerde bunu yapmanız gerekir.

KURU hala geçerlidir.

Daha sonra yeniden düzenlemeyi test etmek için başka bir test yazmam gerekmez mi?

Yapar mısın? Ve şu anda sahip olduğunuz testlerin doğru olduğunu nereden biliyorsunuz?

Yeniden düzenleme işlemini testleri çalıştırarak test edersiniz. Hepsinin sonuçları aynı olmalıdır.


Kesinlikle doğru. Testler koddur - iyi kod yazmak için aynı prensipler hala geçerlidir! Testleri yürüterek yeniden düzenleme işlemini test edin, ancak yeterli kapsama alanı olduğundan ve testlerinizde birden fazla sınır koşulu kullandığınızdan emin olun (örn. Normal bir durum ile arıza durumu).
Michael

6
Katılmıyorum. Testler mutlaka KURU olmak zorunda değildir, DAM (Tanımlayıcı ve Anlamlı İfadeler) olmaları DRY'den daha önemlidir. (Genel olarak, en azından. Bu özel durumda, tekrarlanan başlatmayı bir yardımcıya çıkarmak kesinlikle mantıklıdır.)
Jörg W Mittag

2
Daha önce hiç DAMP duymadım, ama bu açıklamayı beğendim.
Joachim Sauer

@ Jörg W Mittag: Testlerle hala KURU ve DAMP olabilirsiniz. Testin bir kısmının tekrarlandığını bilsem, genellikle testin farklı ARRANGE-ACT-ASSERT (veya GIVEN-WHEN-THEN) parçalarını test fikstüründeki yardımcı yöntemlere tekrar yansıtırım. Genellikle DAMP isimleri vardır, givenThereAreProductsSet(amount)hatta bu kadar basit actWith(param). Bir givenThereAre(2).products()kez akıcı bir şekilde (örneğin ) akıcı bir şekilde yapmayı başardım, ancak hızlı bir şekilde durdum çünkü aşırıya kaçmış gibi hissettim.
Spoike

11

Oded'in daha önce söylediği gibi, test kodunun hala korunması gerekiyor. Test kodundaki bu tekrarı, destekçilerin testlerin yapısını anlamasını ve yeni testler eklemesini zorlaştırdığını ekledim.

Gönderdiğiniz iki işlevde, fordöngünün başlangıcında bir boşluk farkı dışında aşağıdaki satırlar kesinlikle aynıdır :

        int[] a = new int[1000];
        Random rand = new Random(DateTime.Now.Millisecond);
        for (int i = 0; i < a.Length; i++)
        {
            a[i] = rand.Next(Int16.MaxValue);
        }
        int[] b = new int[1000];
        a.CopyTo(b, 0);
        List<int> temp = b.ToList();
        temp.Sort();
        b = temp.ToArray();

Bu, adı veriyi başlattığını belirten bir tür yardımcı işleve geçmek için mükemmel bir aday olacaktır.


4

Hayır tamam değil. Bunun yerine bir TestDataBuilder kullanmalısınız. Ayrıca testlerinizin okunabilirliğine de dikkat etmelisiniz: a? 1000? b? Yarın test ettiğiniz uygulama üzerinde çalışmak zorunda kalırsanız, testler mantığa girmek için harika bir yoldur: testlerinizi derleyici için değil, diğer programcılar için yazın :)

"Yenilenmiş" test uygulamanız:

/**
* Data your tests will exercice on
*/
public class MyTestData(){
    final int [] values;
    public MyTestData(int sampleSize){
        values = new int[sampleSize];
        //Out of scope of your question : Random IS a depencency you should manage
        Random rand = new Random(DateTime.Now.Millisecond);
        for (int i = 0; i < a.Length; i++)
        {
            a[i] = rand.Next(Int16.MaxValue);
        }
    }
    public int [] values();
        return values;
    }

}

/**
* Data builder, with default value. 
*/
public class MyTestDataBuilder {
    //1000 is actually your sample size : emphasis on the variable name
    private int sampleSize = 1000; //default value of the sample zie
    public MyTestDataBuilder(){
        //nope
    }
    //this is method if you need to test with another sample size
    public MyTestDataBuilder withSampleSizeOf(int size){
        sampleSize=size;
    }

    //call to get an actual MyTestData instance
    public MyTestData build(){
        return new MyTestData(sampleSize);
    }
}

public class MergeSortTest { 

    /**
    * Helper method build your expected data
    */
    private int [] getExpectedData(int [] source){
        int[] expectedData =  Arrays.copyOf(source,source.length);
        Arrays.sort(expectedData);
        return expectedData;
    }
}

//revamped tests method Merge
    public void MergeSortAssertArrayIsSorted(){
        int [] actualData = new MyTestDataBuilder().build();
        int [] expected = getExpectedData(actualData);
        //Don't know what 0 is for. An option, that should have a explicit name for sure :)
        MergeSort merge = new MergeSort();
        merge.mergeSort(actualData,0,actualData.length-1); 
        CollectionAssert.AreEqual(actualData, expected);
    }

 //revamped tests method Insertion
 public void InsertionSortAssertArrayIsSorted()
    {
        int [] actualData = new MyTestDataBuilder().build();
        int [] expected = getExpectedData(actualData);
        InsertionSort merge = new InsertionSort();
        merge.insertionSort(actualData);
        CollectionAssert.AreEqual(actualData, expectedData); 
    }
//another Test, for which very small sample size matter
public void doNotCrashesWithEmptyArray()
    {
        int [] actualData = new MyTestDataBuilder().withSampleSizeOf(0).build();
        int [] expected = getExpectedData(actualData);
        //continue ...
    }
}

2

Üretim kodundan daha fazlası olsa da, test kodunun test edilebilir kod boyunca korunması ve belgelerin bir parçası olarak okunması gerektiği için okunabilirlik ve bakım kolaylığı için optimize edilmesi gerekir. Kopyalanan kodun test kodu bakımını nasıl zorlaştırabileceğini ve bunun her şey için test yazmamaya nasıl teşvik edebileceğini düşünün. Ayrıca, testlerinizi KURUTMAK için bir işlev yazdığınızda, bunun da testlere tabi olması gerektiğini unutmayın.


2

Testler için kodu çoğaltmak kolay bir tuzaktır. Uygun olduğundan emin olun, ancak uygulama kodunuzu yeniden düzenlemeye başlar ve testlerinizin değişmeye başlaması durumunda ne olur? Uygulama kodunuzu çoğalttıysanız aynı riskleri uygularsınız, çünkü birçok yerde test kodunuzu değiştirmeniz gerekecektir. Bu, çok fazla boşa harcanan zamana ve ele alınması gereken artan sayıda arıza noktasına katkıda bulunur, bu da yazılımınızı koruma maliyetinin gereksiz derecede yüksek hale geldiği ve dolayısıyla yazılımın genel iş değerini düşürdüğü anlamına gelir. üzerinde çalışmak.

Ayrıca, testlerde yapılması kolay olan şeylerin uygulamada kolaylaşacağını düşünün. Zamana ve çok fazla strese maruz kaldığınızda, insanlar öğrenilmiş davranış kalıplarına güvenme eğilimindedir ve genellikle o zaman en kolay görünen şeyi yapmaya çalışırlar. Bu nedenle, test kodunuzun çoğunu kesip yapıştırdığınızı fark ederseniz, muhtemelen uygulama kodunuzda da aynı şeyi yaparsınız ve bu sizi çok kurtarmak için kariyerinizde erken kaçınmak istediğiniz bir alışkanlıktır Daha sonra, yazdığınız ve şirketinizin yeniden yazmayı göze alamayacağı eski kodları korumak zorunda olduğunuzu fark ettiğinizde.

Diğerlerinin söylediği gibi, DRY prensibini uygularsınız ve yardımcı yöntemlere ve yardımcı sınıflara olası kopyaları yeniden düzenleme fırsatlarını ararsınız ve evet, kodun yeniden kullanımını en üst düzeye çıkarmak ve kaydetmek için bunu testlerinizde bile yapmalısınız daha sonra bakım konusunda zorluklarla karşılaşabilirsiniz. Kendinizi yavaşça, muhtemelen birden fazla projede bile tekrar tekrar kullanabileceğiniz bir test API'sı geliştirirken bulabilirsiniz - kesinlikle son birkaç yıldır benim için böyle oldu.

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.