İkili fonksiyon assert ile gelen problemleri çözme Eşitlikler (beklenen, gerçek)


10

Yıllarca kovboy kodlamasından sonra, kaliteli kodun nasıl yazılacağı hakkında bir kitap almaya karar verdim. Robert Cecil Martin tarafından Temiz Kod okuyorum. Bölüm 3'te (fonksiyonlar) ikili fonksiyonlar hakkında bir bölüm vardır. İşte kitaptan bir alıntı.

Gibi bariz ikili fonksiyonlar bile assertEquals(expected, actual)sorunludur. Gerçek olanı beklenen yere kaç kez koydunuz? İki argümanın doğal düzeni yoktur. Beklenen, gerçek sıralama öğrenmek için pratik gerektiren bir sözleşmedir.

Yazar zorlayıcı bir noktaya değiniyor. Makine öğreniminde çalışıyorum ve her zaman bununla karşılaşıyorum. Örneğin, sklearn kütüphanesindeki tüm metrik fonksiyonlar (muhtemelen alandaki en çok kullanılan python kütüphanesi) girişlerin sırasına dikkat etmenizi gerektirir. Örnek olarak sklearn.metrics.homogeneity_score girdi olarak alır labels_trueve labels_pred. Bu işlevin fazla alakalı olmadığı, ilgili olan şey, girişlerin sırasını değiştirirseniz hiçbir hatanın atılmamasıdır. Aslında, girişlerin değiştirilmesi kütüphanedeki başka bir fonksiyonun kullanılmasına eşdeğerdir .

Ancak kitap gibi işlevler için mantıklı bir düzeltme söylemeye devam etmiyor assertEquals. assertEqualsYukarıda tarif edilenler gibi sık sık karşılaştığım işlevler için ya da işlevler için bir düzeltme düşünemiyorum . Bu sorunu çözmek için iyi uygulamalar nelerdir?

Yanıtlar:


11

Düzeltme olmadığında bile olası bir sorunun farkında olmak iyidir - bu şekilde bu kodu okurken veya yazarken dikkatli olabilirsiniz. Bu özel örnekte, bir süre sonra argümanların sırasına alışacaksınız.

Parametre sıralaması ile ilgili herhangi bir karışıklığı önlemek için dil düzeyinde yollar vardır: adlandırılmış argümanlar. Bu maalesef Java veya C ++ gibi C stili sözdizimine sahip birçok dilde desteklenmemektedir. Ancak Python'da her argüman adlandırılmış bir argüman olabilir. Bir işlevi def foo(a, b)olarak çağırmak yerine foo(1, 2)yapabiliriz foo(a=1, b=2). C # gibi birçok modern dil benzer sözdizimine sahiptir. Smalltalk dil ailesi en uzak olarak adlandırılmış argümanlar almıştır: herhangi bir konumsal argüman yoktur ve her şey adlandırılmıştır. Bu, doğal dile çok yakın okunan kodlara yol açabilir.

Daha pratik bir alternatif, adlandırılmış argümanları simüle eden API'ler oluşturmaktır. Bunlar akıcı API'ler veya doğal bir akış oluşturan yardımcı işlevler olabilir. assertEquals(actual, expected)Adı karıştırıyor. Gördüğüm bazı alternatifler:

  • assertThat(actual, is(equalTo(expected))): yardımcı türlerde bazı bağımsız değişkenleri sararak, kaydırma işlevleri etkin olarak parametre adları işlevi görür. Birim test iddialarının özel durumunda, bu teknik, genişletilebilir ve birleştirilebilir bir onaylama sistemi sağlamak için Hamcrest eşleştiricileri tarafından kullanılır . Buradaki dezavantaj, çok fazla yuvaya sahip olmanız ve çok sayıda yardımcı işlev almanız gerektiğidir. Bu benim C ++ benim go-to tekniği.

  • expect(actual).to.be(expected): dize işlevini birlikte çağırdığınız akıcı bir API. Bu ekstra yuvalamayı önlese de, bu genişletilemez. Akıcı API'lerin çok iyi okuduğunu fark etsem de, iyi bir akıcı API tasarlamak deneyimlerimde çok çaba harcıyor, çünkü çağrı zincirindeki terminal olmayan durumlar için ek sınıflar uygulamanız gerekiyor. Bu çaba, yalnızca bir sonraki izin verilen yöntem çağrılarını önerebilen otomatik tamamlayıcı IDE bağlamında işe yarar.


4

Bu sorunu önlemek için birkaç yöntem vardır. Sizi aradığınız yöntemi değiştirmeye zorlamayan bir yöntem:

Ziyade

assertEquals( 42, meaningOfLife() ); 

kullanım

expected = 42;
actual = meaningOfLife();
assertEquals(expected, actual);

Bu, sözleşmeyi, geçişlerinin fark edilmesinin kolay olduğu açıklığa zorlar. Elbette yazmak o kadar kolay değil ama okunması kolay.

Çağrılan yöntemi değiştirebilirseniz, okunması kolay kullanımı zorlamak için yazma sistemini kullanabilirsiniz.

assertThat( meaningOfLife(), is(42) );

Bazı diller, parametreleri adlandırdıkları için bundan kaçınmanıza izin verir:

assertEquals( expected=42, actual=meaningOfLife() );

Diğerleri onları simüle etmediğiniz için:

assertEquals().expected(42).actual( meaningOfLife() );

Ne yaparsanız yapın, bunu okuduğunuzda doğru olan bir yol bulursunuz. Sözleşmenin ne olduđunu tahmin etmeme izin verme. Göster bana.

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.