Mockito neden statik yöntemlerle alay etmiyor?


267

Burada statik yöntemler hakkında birkaç konu okudum ve statik yöntemlerin yanlış / aşırı kullanımının neden olabileceği sorunları anladığımı düşünüyorum. Ama neden statik yöntemleri alay etmenin zor olduğunu gerçekten anlamadım.

PowerMock gibi diğer alaycı çerçeveleri biliyorum, ama neden Mockito yapamıyor?

Bu makaleyi okudum , ancak yazar kelimeye karşı dini olarak karşı görünüyor static, belki de benim zayıf anlayışım.

Kolay bir açıklama / bağlantı harika olurdu.


12
Sadece bir yan not: PowerMock kendi başına sahte bir nesne kütüphanesi değildir, sadece diğer özellikleri üzerine bu özellikleri (alaycı statikler ve ctors) ekler. PowerMock + Mockito'yu birbirleriyle iyi yüzdükleri işlerde kullanıyoruz.
Matthias

Yanıtlar:


238

Nedeni sahte nesne kitaplıkları genellikle dinamik çalışma zamanı ( cglib kullanarak ) sınıfları oluşturarak alay oluşturmak olabilir düşünüyorum . Bu, çalışma zamanında bir arabirim uyguladıkları (yanılmıyorsam EasyMock'un yaptığı şey) veya sınıftan alay etmek için miras kaldıkları anlamına gelir (Mockito'nun yanılmıyorsam yaptığı şey budur). Her iki yaklaşım da statik üyeler için çalışmaz, çünkü miras kullanarak bunları geçersiz kılamazsınız.

Statik alay etmenin tek yolu , çalışma sırasında bir sınıfın bayt kodunu değiştirmektir .

Bu benim tahminim, değer için ...


7
Aynı şey yapıcı alaycılar için de geçerlidir. Bunlar da miras yoluyla değiştirilemez.
Matthias

11
Bazı TDD / TBD taraftarlarının statik yöntem ve yapıcı alaycılığının eksikliğini iyi bir şey olarak algıladığını da eklemeye değer . Statik yöntemleri veya yapıcıları alay etmek zorunda kaldığınızda, bunun kötü sınıf tasarımının bir göstergesi olduğunu iddia ediyorlar. Örneğin, kod modüllerinizi birleştirirken saf bir IoC yaklaşımını izlerken, ilk etapta statik veya ctorları taklit etmeniz bile gerekmeyecektir (tabii ki bazı kara kutu bileşenlerinin bir parçası olmadıkça). Ayrıca bkz. Giorgiosironi.blogspot.com/2009/11/…
Matthias

200
Alaycı araçların sizin için neyin daha iyi olduğunu bildiklerini varsaymadan ihtiyacınız olan şeyi vermesi gerektiğini düşünüyorum. Örneğin, alay etmem gereken statik yöntem çağrısını kullanan bir üçüncü taraf kitaplığı kullanıyor olsaydım, bunu yapabilmek güzel olurdu. Sahte bir çerçevenin size bazı yetenekler sağlamayacağı fikri kötü tasarım olarak görülmesi temelde kusurludur.
Lo-Tan

11
@ Lo-Tan - bir dilin sizden daha iyi bildiği varsayılarak, bir dilin her şeyi yapabilmesi gerektiğini söylemek gibidir. Bu sadece sizin açınızdan makyaj, çünkü heybetli olarak çıkıyorlar. Buradaki sorun, "anti / pro statik" savaşın açık olmaması ve çerçeveler. İkisine de sahip olmamız gerektiğine katılıyorum. Gerçekler Ama nerede olduğu net bir çerçeve tercih getirir bu gerçekleri. Bu öğrenmenin bir yolu - sizi takip eden araçlar. Yani kendiniz yapmak zorunda değilsiniz. Ama şimdi her erişte başı "iyi tasarım" olarak adlandırılabilir. "Temelde kusurlu" ...
nevvermind

13
@nevvermind Eh? Üst düzey bir dil, size yardımcı olmak ve önemli parçalara odaklanabilmek için gerekli soyutlamalara sahip olmak içindir. Test kütüphanesi bir araçtır - daha kaliteli ve umarım daha iyi tasarlanmış kod üretmek için kullandığım bir araçtır. Başka birinin kötü tasarlanmış kodunu entegre etmek zorunda kaldığımda kullanamayacağım anlamına gelen sınırlamalar olduğunda, bir test / sahte kütüphanenin amacı nedir? İyi düşünülmüş gibi görünmese de, iyi diller var .
Lo-Tan

28

Statik bir yöntemle alay etmeniz gerekiyorsa, kötü bir tasarım için güçlü bir göstergedir. Genellikle, test altındaki sınıfınızın bağımlılığı ile alay edersiniz. Test altındaki sınıfınız, örneğin java.util.Math # sin gibi statik bir yönteme başvuruyorsa, test altındaki sınıfın tam olarak bu uygulamaya ihtiyacı olduğu anlamına gelir (örneğin doğruluk ve hız). Somut bir sinüs uygulamasından soyutlamak istiyorsanız, muhtemelen bir Arayüze ihtiyacınız var (bunun nereye gideceğini görüyorsunuz)?


3
"Statik kalıcı cephesi" gibi üst düzey soyutlamalar sağlamak için statik yöntemler kullandım. Böyle bir cephe, müşteri kodunu bir ORM API'sinin karmaşıklıklarından ve düşük düzeyli ayrıntılarından uzak tutar, daha tutarlı ve kullanımı kolay bir API sağlar ve aynı zamanda çok fazla esnekliğe izin verir.
Rogério

Ve neden alay etmek zorundasın? Statik yönteme bağlıysanız, "birim" veya "modül" yalnızca sınıf değildir, aynı zamanda "statik kalıcı cepheyi" de içerir.
Ocak

88
Doğru, ancak bazen, örneğin bazı üçüncü taraf sınıflarındaki statik bir yöntemi taklit etmeniz gerekiyorsa, başka seçeneğiniz olmayabilir.
Stijn Geukens

6
Doğru, ama bazen singletonlarla uğraşıyor olabiliriz.
Manu Manjunath

Soyutlama ile çözülemeyen tek düşünce çok fazla soyutlama seviyesidir ... Soyutlama katmanları eklemek karmaşıklık yaratır ve genellikle gereksizdir. Bu basit çağrıyı tek bir sınıfa sararak System.currentTimeMillis () ile dalga geçmeye çalışan çerçeveleri gördüğüm örnekleri düşünüyorum. Sonunda sadece yöntemlere sahip olmak yerine yöntem başına tek bir sınıfla karşılaşırız - sadece testi kolaylaştırmak için. Ve sonra tekli sargıcınız yerine doğrudan statik yöntemi çağıran bir 3. taraf dep tanıttığınızda, testler yine de başarısız oluyor ...
Fr Jeremy Krieg

5

Ciddi statik yöntemleri de alay gerekiyorsa kod kokusu olduğunu düşünüyorum.

  • Ortak işlevselliğe erişmek için statik yöntemler? -> Tek bir örnek kullanın ve
  • Üçüncü taraf kodu mu? -> Kendi arayüzünüze / temsilcinize sarın (ve gerekirse tek birton yapın)

Bu benim için aşırı dolu gibi görünen tek zaman, Guava gibi kütüphaneler, ama yine de bu türden alay etmenize gerek yok çünkü mantığın bir parçası ... (Iterables.transform (..) gibi)
Kendi kodunuz bu şekilde temiz kalır, tüm bağımlılıklarınızı temiz bir şekilde alay edebilirsiniz ve dış bağımlılıklara karşı bir yolsuzlukla mücadele katmanınız vardır. PowerMock'u pratikte gördüm ve ihtiyaç duyduğumuz tüm sınıflar kötü tasarlanmıştı. Ayrıca PowerMock'un zaman zaman entegrasyonu ciddi sorunlara neden oldu
(örn. Https://code.google.com/p/powermock/issues/detail?id=355 )

Not: Aynı şey özel yöntemler için de geçerlidir. Testlerin özel yöntemlerin ayrıntıları hakkında bilmesi gerektiğini düşünmüyorum. Eğer bir sınıf o kadar karmaşıksa, özel yöntemleri alay etmek isterse, muhtemelen o sınıfı bölmek için bir işarettir ...


2
Singleton, özellikle birden fazla örneğe ihtiyacınız olduğunu fark ettiğinizde ve şimdi bunun gerçekleşmesi için tüm sisteminizi yeniden düzenlemeniz gerektiğinde, her türlü sorunla karşılaşmanızı sağlayacaktır.
Ricardo Freitas

Singleton Paternini herkese tavsiye ettiğimi söylemedim. Demek istediğim, statik bir yardımcı sınıf ve aynı işlevselliği sunan bir Singleton arasında karar vermek zorunda kalırsam, Singleton'u seçerdim. Ve eğer bir sınıf Singleton ise ya da değil ise yine de DI çerçevesi tarafından kontrol edilmelidir, benim sınıfımda @Inject SomeDependencyve benim konfigürasyonumda tanımlarım bind(SomeDependency.class).in(Singleton.class). Bu yüzden yarın artık bir Singleton değilse, tek yapılandırmayı değiştiriyorum ve hepsi bu.
pete83

@ pete83 Seni duyuyorum kardeşim. Bununla birlikte, test kütüphanelerinin veya geliştiricilerin test çerçevesinin tasarımını / sınırlarını karşılamak için tasarımlarını değiştirmelerini gerektiren bir sorunum var. IMO attan önce arabayı ya da köpeği sallayan kuyruğu koyuyor.
Matt Campbell

1
Bu argüman bana pek mantıklı gelmiyor. Singleton kalıpları, burada listelemek için çok fazla nedenden dolayı yıllardır gözden düştü. "Temiz" kod nedir? Bazı G / Ç işlemi döndüren statik bir yardımcı yöntem çağıran bir sınıf örneği yöntemi varsa, neden bir sınava alay istemiyorum? Peki bu kötü tasarım nasıl? Alaycı statik yöntemleri çevreleyen bu el sıkmalarının hepsi toplanmaz. Bir yöntemi alay etmek, onu test etmenin tersidir. E? Er çok sonra uygulamaya zor sadece söylemek ve onu yapılabilir
eggmatters

Ah adamım, asla herkesin Foo.getInstance()her yerde aradığı eski okul Singleton modelinden bahsetmedim . Ben sadece argümanı karşı koymak için cevap singleton yazdım "ama statik bir yöntem birçok sarıcı nesnelerin oluşturulmasını gerektirmez". Ayrıca kavramsal olarak benim için tek bir statik yöntem ile bir örnek yöntem arasında çok az fark vardır, sadece bu tektonlu ortak çalışanla alay edemezsiniz. Ama singleton ya da değil kesinlikle yapmaya çalıştığım nokta değil, asıl nokta, işbirlikçileri enjekte etmek ve alay etmek ve testi zorlaştırırsa statik yöntemleri çağırmamaktır.
pete83

4

Mockito nesneleri döndürür ancak statik, "sınıf düzeyi, nesne düzeyi değil" anlamına gelir. Böylece mockito, statik için boş işaretçi istisnası verecektir.


0

Bazı durumlarda, statik yöntemlerin test edilmesi zor olabilir, özellikle de alay edilmeleri gerekiyorsa, bu nedenle çoğu alaycı çerçevenin bunları desteklememesi gerekir. Bu blog gönderisinin statik yöntemler ve sınıflarla alay etmeyi belirlemede çok yararlı olduğunu gördüm .


1
Statik yöntemlerin alay edilmesi, uygun bir alaycı API kullanıldığında örnek yöntemlerinin alay edilmesinden daha kolaydır (örnek olmadığı için).
Rogério

Bu, soruyu sorunun kendisiyle cevaplamak gibidir, bu yüzden bunu yapmak zordur, bunun bir cevap değildir.
Matthias

40
Blog yayını, aslında , bir sınıfı, kullanılan statik yöntemlerden ayırma sorununu çözmek yerine, (üretim kodunu yeniden düzenleyerek) maliyetli bir geçici çözüm önerdiğinden aşağı indirdim . Gerçekten işi yapan bir alay aracı olan IMO, herhangi bir yöntemle ayrımcılık yapmaz; bir geliştirici, belirli bir durumda statik yöntemlerin kullanılmasının tek bir yolda zorlanmak yerine iyi veya kötü olduğuna karar vermekte serbest olmalıdır.
Rogério
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.