Bir enkoderi nasıl test ediyorsunuz?


9

Böyle bir şey var:

public byte[] EncodeMyObject(MyObject obj)

Bu şekilde birim test yaptım:

byte[] expectedResults = new byte[3]{ 0x01, 0x02, 0xFF };
Assert.IsEqual(expectedResults, EncodeMyObject(myObject));

DÜZENLEME: Önerilen gördüğüm iki yol:

1) Yukarıdaki örnek gibi sabit kodlanmış beklenen değerleri kullanma.

2) Kodlanmış bayt dizisinin kodunu çözmek için bir dekoder kullanmak ve giriş / çıkış nesnelerini karşılaştırmak.

Yöntem 1 ile gördüğüm sorun çok kırılgan ve çok sayıda sabit kodlanmış değer gerektiriyor olmasıdır.

Yöntem 2'deki sorun, kodlayıcıyı test etmenin kod çözücünün doğru çalışmasına bağlı olmasıdır. Kodlayıcı / kod çözücü eşit olarak kırılırsa (aynı yerde), testler yanlış pozitifler üretebilir.

Bu tür bir yöntemi test etmenin tek yolu bunlar olabilir. Eğer durum buysa, o zaman iyi. Bu tür testler için daha iyi stratejiler olup olmadığını görmek için soruyu soruyorum . Üzerinde çalıştığım belirli kodlayıcının iç kısımlarını açığa çıkaramıyorum. Genel olarak bu tür bir problemi nasıl çözeceğinizi soruyorum ve içselliğin önemli olduğunu düşünmüyorum. Belirli bir giriş nesnesinin her zaman aynı çıkış bayt dizisini üreteceğini varsayın.


4
Nasıl yok myObjectgitmek myObjectiçin { 0x01, 0x02, 0xFF }? Bu algoritma parçalanıp test edilebilir mi? Sormamın nedeni şu anda, sihirli bir şeyin başka bir sihirli şey ürettiğini kanıtlayan bir testiniz var gibi görünüyor. Tek güveniniz, bir girdinin bir çıktıyı üretmesidir. Algoritmayı parçalayabilirseniz, algoritmaya daha fazla güvenebilir ve büyülü giriş ve çıkışlara daha az güvenebilirsiniz.
Anthony Pegram

3
@ Kodlama Enkoder ve dekoder aynı yerde kırılırsa ne olur?
ConditionRacer

2
Testler, tanım gereği, bir şey yapmak ve beklenen sonuçları alıp almadığınızı kontrol etmek için yapılır, bu da testinizin yaptığı şeydir. Elbette, tüm kodunuzu kullandığınızdan ve kenar durumlarını ve diğer tuhaflıkları kullandığınızdan emin olmak için yeterli testler yaptığınızdan emin olmanız gerekir.
Blrfl

1
@ Justin984, şimdi daha derine gidiyoruz. Bu özel dahili kodlayıcıları Encoder API'sının üyeleri olarak göstermem, kesinlikle değil. Onları Encoder'dan tamamen çıkarırdım. Ya da, Enkoder başka bir yere, bir bağımlılığa delege olur . Eğer test edilemeyen bir canavar yöntemi ya da bir grup yardımcı sınıf arasındaki bir savaşsa, her seferinde yardımcı sınıfları seçiyorum. Ama yine de, bu noktada kodunuza bilgisiz çıkarımlarda bulunuyorum, çünkü göremiyorum. Ancak testlerinize güvenmek istiyorsanız, daha az şey yapmak için daha küçük yöntemlere sahip olmak oraya ulaşmanın bir yoludur.
Anthony Pegram

1
@ Justin984 Spesifikasyon değişirse, testinizde beklenen çıktıyı değiştirirsiniz ve şimdi başarısız olur. Sonra geçmek için kodlayıcı mantığını değiştirin. TDD'nin tam olarak nasıl çalışması gerekiyor gibi görünüyor ve sadece gerektiğinde başarısız olacak. Bunun nasıl kırılgan hale geldiğini anlamıyorum.
Daniel Kaplan

Yanıtlar:


1

Orada biraz iğrenç bir durumdasınız. Eğer kodladığınız statik bir biçiminiz olsaydı, ilk yönteminiz gitmenin yolu olurdu. Sadece kendi biçiminiz olsaydı ve ikinci yöntemden başka hiç kimsenin kodunu çözmesi gerekmiyorsa, yol bu olurdu. Ancak bu kategorilerden hiçbirine uymuyorsunuz.

Yapacağım şey, soyutlama düzeyine göre işleri parçalamaya çalışmak.

Böylece bit seviyesinde bir şeyle başlayacağım,

bitWriter = new BitWriter();
bitWriter.writeInt(42, bits = 7);
assertEqual( bitWriter.data(), {0x42} )

Yani fikir, yazarın ints gibi en ilkel alan türlerini nasıl yazacağını bilmesi.

Daha karmaşık türler aşağıdakiler kullanılarak uygulanacak ve test edilecektir:

bitWriter = new BitWriter();
writeDate(bitWriter, new Datetime(2001, 10, 4));

bitWriter2 = new BitWriter();
bitWriter2.writeInt(2001, 12)
bitWriter2.writeInt(10, 4)
bitWriter2.writeInt(4, 6)

assertEquals(bitWriter.data(), bitWriter2.data() )

Bunun, gerçek bitlerin nasıl paketlendiğine dair herhangi bir bilgiden kaçındığına dikkat edin. Bu önceki test tarafından test edildi ve bu test için hemen hemen işe yaradığını varsayacağız.

Sonra bir sonraki soyutlama seviyesinde

bitWriter = new BitWriter();
encodeObject(bitWriter, myObject);


bitWriter2 = new BitWriter();
bitWriter2.writeInt(42, 32)
writeDate(bitWriter2, new Datetime(2001, 10, 4));
writeVarString(bitWriter2, "alphanumeric");

assertEquals(bitWriter.data(), bitWriter2.data() )

dolayısıyla, varstring'lerin, tarihlerin veya sayıların gerçekte nasıl kodlandığına dair bilgileri eklemeye çalışmaz. Bu testte sadece encodeObject tarafından üretilen kodlama ile ilgileniyoruz.

Sonuç olarak, tarihlerin biçimi değiştirilirse, tarihleri ​​içeren testleri düzeltmeniz gerekir, ancak diğer tüm kod ve testler, tarihlerin gerçekte nasıl kodlandığına ve yapmak için kodu güncelledikten sonra ilgilenmez. bu testlerin hepsi iyi geçecek.


Bunu severim. Diğer yorumculardan bazılarını daha küçük parçalara ayırmak için söylediklerini sanırım. Spesifikasyon değiştiğinde problemden tamamen kaçınmaz, ancak daha iyi hale getirir.
ConditionRacer

6

Bağlı olmak. Kodlama tamamen sabit bir şeyse, her uygulamanın tam olarak aynı çıktıyı oluşturması gerekiyorsa, örnek girişlerin beklenen çıktılarla tam olarak eşleştiğini doğrulamaktan başka bir şey kontrol etmek mantıklı değildir. Bu en bariz testtir ve muhtemelen en kolay yazılan testtir.

MPEG standardında olduğu gibi alternatif çıkışlara sahip kıpır kama odası varsa (örneğin, girdiye uygulayabileceğiniz belirli operatörler vardır, ancak çıktı kalitesi veya depolama alanına göre kodlama çabasını takas etmekte serbestsiniz), o zaman çıktıya kod çözme stratejisini tanımladı ve girdiyle aynı olduğunu doğrulayın - veya kodlama kayıpsa orijinal girdiye oldukça yakın olduğunu doğrulayın. Bu programlanması daha zordur, ancak sizi kodlayıcınızda yapılabilecek geliştirmelere karşı korur.


2
Kod çözücüyü kullandığınızı ve değerleri karşılaştırdığınızı varsayalım. Enkoder ve dekoder aynı yerde kırılırsa ne olur? Kodlayıcı yanlış kodlar ve kod çözücü yanlış kod çözer, ancak işlem iki kez yanlış yapıldığı için giriş / çıkış nesneleri doğrudur.
ConditionRacer

@ Justin984 sonra "test vektörleri" denilen kullanın, bir kodlayıcı ve kod çözücü test etmek için tam olarak kullanabileceğiniz giriş / çıkış çiftlerini bilmek
cırcır ucube

@ratchet freak Bu beni beklenen değerlerle teste geri getiriyor. Bu iyi, şu anda yaptığım şey bu, ama biraz kırılgan, bu yüzden daha iyi yollar olup olmadığını görmek için bakıyordum.
ConditionRacer

1
Standardı dikkatlice okumak ve her kural için bir test senaryosu oluşturmak dışında, hem kodlayıcının hem de kod çözücünün aynı hatayı içermesinden kaçınmanın bir yolu yoktur. Örneğin, "ABC" nin "xyz" e çevrilmesi gerektiğini varsayalım, ancak kodlayıcı bunu bilmiyor ve kod çözücünüz bu sorunla karşılaşırsa "xyz" yi anlamayacaktır. El işi test senaryoları "ABC" dizisini içermez, çünkü programcı bu kuralın farkında değildi ve ayrıca hem kodlayıcı hem de kod çözücü sorunu göz ardı ettiği için rastgele dizeleri kodlayan / kod çözen bir test yanlış geçecekti.
user281377

1
Eksik bilgi nedeniyle kendi yazdığınız kod çözücüleri ve kodlayıcıları etkileyen hataları yakalamaya yardımcı olmak için, diğer satıcılardan kodlayıcı çıktıları elde etmek için çaba gösterin; ve kodlayıcının çıktısını üçüncü taraf kod çözücülerde test etmeye çalışın. Etrafında bir alternatif yok.
rwong

3

Bunu test edin encode(decode(coded_value)) == coded_valueve decode(encode(value)) == value. İsterseniz testlere rastgele bir giriş yapabilirsiniz.

Hem kodlayıcının hem de kod çözücünün tamamlayıcı yollarla kırılması hala mümkündür, ancak kodlama standardını kavramsal olarak yanlış anlamadığınız sürece bu pek olası görünmemektedir. Kodlayıcı ve kod çözücünün (önceden yaptığınız gibi) sabit kodlu testlerini yapmak, buna karşı korunmalıdır.

Bunun çalıştığı bilinen başka bir uygulamasına erişiminiz varsa, en azından bunu birim testlerinde kullanmak imkansız olsa bile uygulamanızın iyi olduğuna dair güven elde etmek için kullanabilirsiniz.


Tamamlayıcı bir kodlayıcı / kod çözücü hatasının genel olarak olası olmadığını kabul ediyorum. Benim özel durumumda, kodlayıcı / kod çözücü sınıflarının kodu, bir veritabanındaki kurallara dayalı olarak başka bir araç tarafından oluşturulur. Bu nedenle, zaman zaman tamamlayıcı hatalar meydana gelir.
ConditionRacer

'Tamamlayıcı hatalar' nasıl olabilir? Bu, kodlanmış form için harici bir spesifikasyonun ve dolayısıyla harici bir kod çözücünün olduğunu ima eder.
kevin cline

Harici kelimeyi kullanımınızı anlamıyorum. Ancak verilerin nasıl kodlandığına ve ayrıca bir kod çözücüye ilişkin bir spesifikasyon vardır. Tamamlayıcı bir hata, kodlayıcının ve kod çözücünün tamamlayıcı ancak spesifikasyondan farklı bir şekilde çalıştığı yerdir. Orijinal sorunun altındaki yorumlarda bir örnek var.
ConditionRacer

Kodlayıcının ROT13 uygulaması gerekiyordu, ancak yanlışlıkla ROT14 yaptıysa ve kod çözücü de yaptıysa, kod çözme (kodlama ('a')) == 'a' ama kodlayıcı hala bozuk. Bundan çok daha karmaşık şeyler için, muhtemelen bu tür bir şeyin gerçekleşmesi daha az olasıdır, ancak teorik olarak olabilir.
Michael Shaw

@MichaelShaw sadece bir parça trivia, ROT13 için kodlayıcı ve kod çözücü aynı; ROT13 kendi tersidir. ROT14'ü yanlışlıkla uyguladıysanız, decode(encode(char))eşit charolmaz (eşit olur char+2).
Tom Marthenal

2

Gereksinimleri test edin .

Gereksinimler yalnızca 'kodu çözüldüğünde eşdeğer bir nesne üreten bir bayt akışına kodla' ise, kod çözerek kodlayıcıyı test edin. Hem kodlayıcıyı hem de kod çözücüyü yazıyorsanız, bunları birlikte test edin. "Eşleme hataları" olamazlar. Birlikte çalışırlarsa test geçer.

Veri akışı için başka gereksinimler varsa, şifrelenmiş verileri inceleyerek bunları test etmeniz gerekir.

Kodlanmış biçim önceden tanımlanmışsa, kodlanmış verileri yaptığınız gibi beklenen sonuca göre doğrulamanız veya (daha iyi) doğrulamayı yapmak için güvenilir olabilecek bir referans kod çözücü elde etmeniz gerekir. Referans kod çözücünün kullanılması, format spesifikasyonunu yanlış yorumlama olasılığınızı ortadan kaldırır.


1

Test çerçevesine ve kullandığınız paradigmaya bağlı olarak, yine de, bunun için, söylediğin gibi, Eylem Düzenleme Düzenini Düzenle'yi kullanabilirsiniz.

[TestMethod]
public void EncodeMyObject_ForValidInputs_Encodes()
{
    //Arrange object under test
    MyEncoder encoderUnderTest = new MyEncoder();
    MyObject validObject = new MyOjbect();
    //arrange object for condition under test

    //Act
    byte[] actual = encoderUnderTest.EncodeMyObject(myObject);

    //Assert
    byte[] expected = new byte[3]{ 0x01, 0x02, 0xFF };
    Assert.IsEqual(expected, actual);
}

EncodeMyObject()Bu kalıbın gereksinimlerini bilmelisiniz ve her birini düzenleyerek expectedve kod çözücü için benzer şekilde , beklenen sonucu zor kodlayarak, geçerli ve geçersiz kriterler için her birini test etmek için kullanabilirsiniz .

Beklenenler kodlanmış olduğundan, büyük bir değişikliğiniz varsa bunlar kırılgan olacaktır.

Sen (bir göz tahrik şey parametre ile otomatik hale getirmek mümkün olabilir Pex ) veya DDD veya BDD yapıyorsanız bir göz Gerkin / salatalık .


1

Sizin için neyin önemli olduğuna siz karar verirsiniz.

Bir Nesnenin gidiş-dönüşte hayatta kalması sizin için önemli mi ve kesin kablo biçimi gerçekten önemli değil mi? Veya tam tel biçimi kodlayıcı ve kod çözücünüzün işlevselliğinin önemli bir parçası mıdır?

Eğer eski, sadece nesnelerin gidiş-dönüş hayatta kalmak emin olun. Kodlayıcı ve kod çözücünün her ikisi de tamamen tamamlayıcı şekillerde kırılırsa, gerçekten umursamazsınız.

İkincisi ise, tel formatının verilen girişler için beklediğiniz gibi olduğunu test etmeniz gerekir. Bu, biçimi doğrudan test etmek veya başka bir referans uygulaması kullanmak anlamına gelir. Ancak temelleri test ettikten sonra, toplu olarak daha kolay yazılması gereken ek gidiş-dönüş testlerinden değer alabilirsiniz.

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.