Yalnızca birim testleri sırasında kullanılan yöntemleri tanıtmak uygun mudur?


12

Geçenlerde bir fabrika yöntemi TDD yapıyordum. Yöntem ya düz bir nesne ya da bir dekoratöre sarılmış bir nesne yaratmaktı. Dekore edilmiş nesne, StrategyClass'ı genişleten çeşitli türlerden biri olabilir.

Testimde, iade edilen nesnenin sınıfının beklendiği gibi olup olmadığını kontrol etmek istedim. Düz nesne işletim sistemi geri döndüğünde bu kolaydır, ancak bir dekoratör içine sarıldığında ne yapmalı?

Ben ext/Reflectionsarılmış nesne sınıfı bulmak için kullanabilirsiniz böylece PHP kod , ama bana aşırı karmaşık şeyler gibi görünüyordu ve biraz TDD kuralları agains.

Bunun yerine getClassName()StrategyClass den çağrıldığında nesnenin sınıf adını döndürmek tanıtmak karar verdi . Ancak dekoratörden çağrıldığında, aynı yöntemle dekore edilmiş nesnede döndürülen değeri döndürür.

Daha açık hale getirmek için bazı kodlar:

interface StrategyInterface {
  public function getClassName();
}

abstract class StrategyClass implements StrategyInterface {
  public function getClassName() {
    return \get_class($this);
  }
}

abstract class StrategyDecorator implements StrategyInterface {

  private $decorated;

  public function __construct(StrategyClass $decorated) {
    $this->decorated = $decorated;
  }

  public function getClassName() {
    return $this->decorated->getClassName();
  }

}

Ve bir PHPUnit testi

 /**
   * @dataProvider providerForTestGetStrategy
   * @param array $arguments
   * @param string $expected
   */
  public function testGetStrategy($arguments, $expected) {

    $this->assertEquals(
      __NAMESPACE__.'\\'.$expected,  
      $this->object->getStrategy($arguments)->getClassName()
    )
  }

//below there's another test to check if proper decorator is being used

Demek istediğim şu ki: Birim testleri kolaylaştırmaktan başka bir faydası olmayan bu yöntemleri tanıtmak uygun mudur? Bir şekilde bana doğru gelmiyor.


Muhtemelen bu soru, sorunuz hakkında daha fazla fikir verecektir, programcılar.stackexchange.com/ questions/ 231237/…, bunun kullanıma ve geliştirdiğiniz uygulamaların birim testine ve hata ayıklamasına büyük ölçüde yardımcı olup olmayacağına inanıyorum. .
Clement Mark-Aaba

Yanıtlar:


13

Düşüncem hayır, sadece test edilebilirlik için gerekli olduğu için hiçbir şey yapmamalısınız . İnsanların test edilebilirlikten yararlanabileceği birçok karar ve test edilebilirlik ana fayda bile olabilir, ancak diğer esaslar için iyi bir tasarım kararı olmalıdır. Bu, istenen bazı özelliklerin test edilemediği anlamına gelir. Başka bir örnek, bazı rutinin ne kadar verimli olduğunu bilmeniz gerektiğinde, örneğin Hashmap'ınız eşit dağıtılmış bir karma değer aralığı kullanıyorsa - harici arayüzdeki hiçbir şey bunu size söyleyemez.

Düşünmek yerine, "doğru strateji sınıfını alıyorum" düşünüyor "aldığım sınıf bu özelliğin test etmeye çalıştığı şeyi yapıyor mu?" İç sıhhi tesisatı test edebildiğinizde güzel, ancak zorunda değilsiniz, sadece düğmeyi çevirip sıcak veya soğuk su alıp almadığınızı test edin.


+1 OP, TDD özellik testini değil, 'şeffaf kutu' birim testini açıklıyor
Steven A. Lowe

1
Fabrika yönteminin işini yapıp yapmadığını test etmek istediğimde, StrategyClass algoritmalarının testlerini eklemek için biraz isteksiz olmama rağmen, sivri görüyorum. Bu tür izolasyon IMHO'yu kırar. Bundan kaçınmak için başka bir neden, bu belirli sınıfların veritabanı üzerinde çalışması, bu yüzden onları test ek alay / stubbing gerektirir.
Mchl

Öte yandan ve bu sorunun ışığında: "TDD testlerini" "birim testlerinden" ayırdığımızda programmers.stackexchange.com/questions/86656/… bu mükemmel bir hal alıyor (yine de veritabanı tesisatına rağmen: P)
Mchl

Yöntemleri eklerseniz, kullanıcılarınızla yapılan sözleşmenin bir parçası haline gelirler. Sonuçlara göre sadece test fonksiyonlarınızı ve şubenizi çağıran kodlayıcılarla sonuçlanacaksınız. Genel olarak, mümkün olduğunca az sınıfa maruz kalmayı tercih ederim.
BillThor

5

Bunu benim almam - bazen daha test edilebilir hale getirmek için kaynak kodunuzu biraz yeniden işlemeniz gerekir. İdeal değildir ve arayüzü sadece test için kullanılması gereken işlevlerle karıştırmak için bir mazeret olmamalıdır, bu nedenle ılımlılık genellikle burada anahtardır. Kodunuzun kullanıcılarının, nesnenizle normal etkileşimler için aniden test arabirimi işlevlerini kullandıkları durumda da olmak istemezsiniz.

Bunu işlemek için tercih ettiğim yol (ve ben esas olarak C tarzı dillerde kod olarak PHP bunu nasıl gösteremiyorum özür dilemek zorundayım) 'test' işlevleri olmayan bir şekilde sağlamaktır nesnenin kendisi tarafından dış dünyaya maruz kalır, ancak türetilmiş nesneler tarafından erişilebilir. Test amaçlı olarak, aslında test etmek istediğim nesne ile etkileşimi idare edecek bir sınıf türetirdim ve birim testin o nesneyi kullanmasını sağlarım. Bir C ++ örneği şöyle görünecektir:

Üretim tipi sınıfı:

class ProdObj
{
  ...
  protected:
     virtual bool checkCertainState();
};

Test yardımcı sınıfı:

class TestHelperProdObj : public ProdObj
{
  ...
  public:
     virtual bool checkCertainState() { return ProdObj::checkCertainState(); }
};

Bu şekilde, en azından ana nesnenizdeki 'test' türü işlevlerini göstermeniz gerekmeyen bir konumdasınız demektir.


İlginç bir yaklaşım. Bunu nasıl adapte edebileceğimi görmem gerek
Mchl

3

Birkaç ay önce yeni satın aldığım bulaşık makinesini yerleştirdiğimde hortumundan çok fazla su geldi, bunun muhtemelen geldiği fabrikada düzgün bir şekilde test edilmesinden kaynaklandığını fark ettim. Bir montaj hattında test etmek için orada bulunan makinelerde montaj deliklerini ve malzemelerini görmek nadir değildir.

Test etmek önemlidir, eğer gerekiyorsa, bunun için bir şeyler ekleyin.

Ancak bazı alternatifleri deneyin. Yansıtma tabanlı seçeneğiniz o kadar da kötü değil. İhtiyacınız olan şeylere karşı korumalı bir sanal erişimciniz olabilir ve test etmek ve iddia etmek için türetilmiş bir sınıf oluşturabilirsiniz. Belki de sınıfınızı bölebilir ve ortaya çıkan bir yaprak sınıfını doğrudan test edebilirsiniz. Test yöntemini kaynak kodunuzda bir derleyici değişkeniyle gizlemek de bir seçenektir (PHP'yi bilmiyorum, PHP'de mümkün olup olmadığından emin değilim).

Bağlamınızda, dekoratör içinde uygun kompozisyonu test etmemeye karar verebilirsiniz, ancak dekorasyonun olması gereken beklenen davranışı test edebilirsiniz. Bu belki de biraz daha beklenen sistem davranışına odaklanır ve teknik şartnameye çok fazla odaklanmaz (dekoratör modeli sizi fonksiyonel bir perspektiften ne satın alır?).


1

Ben mutlak bir TDD acemi değilim, ama eklenen yönteme bağlı gibi görünüyor. TDD'den anladığım kadarıyla, testlerinizin API'nızın oluşturulmasını bir dereceye kadar "yönlendirmesi" gerekiyor.

Tamam olduğunda:

  • Yöntem kapsüllemeyi bozmadığı ve nesnenin sorumluluğuna uygun bir amaca hizmet ettiği sürece.

Tamam olmadığında:

  • Yöntem hiçbir zaman yararlı olmayacak veya diğer arayüz yöntemleriyle ilgili olarak anlamlı olmayan bir şey gibi görünüyorsa, yapışkan veya kafa karıştırıcı olabilir. Bu noktada, o nesneyi anlamam çamur olurdu.
  • Jeremy'nin örneği, "... bazı rutinlerin ne kadar verimli olduğunu bilmeniz gerektiğinde, örneğin Hashmap'ınız eşit dağıtılmış bir karma değer aralığı kullanıyor - harici arayüzdeki hiçbir şey bunu size söyleyemez."
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.