SavePeople () birim test edilmeli
Evet, olmalı. Ancak test koşullarınızı uygulamadan bağımsız bir şekilde yazmaya çalışın. Örneğin, kullanım örneğinizi birim testine dönüştürmek:
function testSavePeople() {
myDataStore = new Store('some connection string', 'password');
myPeople = ['Joe', 'Maggie', 'John'];
savePeople(myDataStore, myPeople);
assert(myDataStore.containsPerson('Joe'));
assert(myDataStore.containsPerson('Maggie'));
assert(myDataStore.containsPerson('John'));
}
Bu test çok şey yapar:
- işlevin sözleşmesini doğrular
savePeople()
- uygulanması umurunda değil
savePeople()
- örnek kullanımını belgeliyor
savePeople()
Veri deposunu hala alay / taslak / taklit edebileceğinizi unutmayın. Bu durumda, açık fonksiyon çağrıları için kontrol yapmazdım ama işlemin sonucunu kontrol ederim. Bu şekilde testim gelecekteki değişikliklere / refaktörlere hazırlanır.
Örneğin, veri deposu uygulamanız saveBulkPerson()
gelecekte bir yöntem sağlayabilir - şimdi savePeople()
kullanımının uygulanmasında yapılan bir değişiklik , beklendiği saveBulkPerson()
kadar uzun sürdüğü sürece ünite testini saveBulkPerson()
bozmaz. Ve eğer bir saveBulkPerson()
şekilde beklendiği gibi çalışmazsa, birim testiniz bunu yakalayacaktır.
ya da bu tür testler, forEach dil yapısının yerleşik olarak test edilmesini sağlar mı?
Belirtildiği gibi, uygulama için değil (entegrasyon testleri yapmıyorsanız - o zaman belirli işlev çağrılarını kullanmak kullanımda olabilir) beklenmeyen sonuçları ve işlev arayüzünü test etmeye çalışın. Bir işlevi uygulamak için birden fazla yol varsa, bunların tümü birim testinizde çalışmalıdır.
Sorunun güncellenmesiyle ilgili olarak:
Durum değişikliklerini test edin! Örneğin bazı hamurlar kullanılacaktır. Senin uygulanmasına göre, kullanılan miktarı iddia dough
sığar pan
veya iddia dough
tüketilir. pan
İşlev çağrısından sonra çerezleri içerdiğini kabul edin . oven
Boş olduğunu ve eskisi gibi aynı durumda olduğunu kabul edin.
Ek testler için son durumları doğrulayın: oven
Aramadan önce boş değilse ne olur ? Yeterli yoksa ne olur dough
? Eğer pan
zaten dolu?
Bu testler için gerekli tüm verileri hamur, tava ve fırın nesnelerinden çıkarabilmelisiniz. İşlev çağrılarını yakalamaya gerek yok. Fonksiyonu, uygulaması sizin için uygun olmayacak gibi düşünün!
Aslında, çoğu TDD kullanıcısı, fonksiyonlarını yazmadan önce testlerini yapar, böylece gerçek uygulamaya bağlı olmazlar.
En son eklemeniz için:
Bir kullanıcı yeni bir hesap oluşturduğunda, bazı şeylerin olması gerekir: 1) veritabanında yeni bir kullanıcı kaydı oluşturulması gerekir 2) karşılama e-postası gönderilir 3) kullanıcının IP adresinin dolandırıcılık için kaydedilmesi gerekir amaçlar.
Bu nedenle, tüm "yeni kullanıcı" adımlarını birbirine bağlayan bir yöntem oluşturmak istiyoruz:
function createNewUser(validatedUserData, emailService, dataStore) {
userId = dataStore.insertUserRecord(validateduserData);
emailService.sendWelcomeEmail(validatedUserData);
dataStore.recordIpAddress(userId, validatedUserData.ip);
}
Bunun gibi bir fonksiyon için, ack / stub / fake (ne daha genel görünüyorsa) dataStore
ve emailService
parametrelerini alayım. Bu işlev kendi başına herhangi bir parametre üzerinde herhangi bir durum geçişi yapmaz, onları bazılarının yöntemlerine devreder. Fonksiyon çağrısının 4 şey yaptığını doğrulamaya çalışacağım:
- bir kullanıcıyı veri deposuna ekledi
- bir hoşgeldin e-postası (veya en azından karşılık gelen yöntem olarak adlandırılır) gönderdi
- kullanıcıların IP'sini veri deposuna kaydetti
- karşılaştığı herhangi bir istisnayı / hatayı temsil etti (varsa)
İlk 3 denetler mocks, taslakları veya sahte ile yapılabilir dataStore
ve emailService
(gerçekten test ederken e-postalar göndermek istemiyorum). Bazı yorumlar için bunu aramam gerektiğinden, bunlar arasındaki farklar:
- Sahte, orijinalle aynı şekilde davranan ve belli bir ölçüde ayırt edilemeyen bir nesnedir. Kodu normalde testlerde tekrar kullanılabilir. Bu, örneğin, bir veritabanı sarıcısı için basit bir bellek içi veritabanı olabilir.
- Bir saplama sadece bu testin gerekli işlemlerini yerine getirmek için gereken kadar uygular. Çoğu durumda, bir saplama bir teste veya yalnızca orijinal yöntemlerin küçük bir setini gerektiren bir test grubuna özgüdür. Bu örnekte,
dataStore
sadece insertUserRecord()
ve 'nin uygun bir versiyonunu uygulayan olabilir recordIpAddress()
.
- Sahte, nasıl kullanıldığını doğrulamanıza izin veren bir nesnedir (çoğunlukla çağrıları yöntemlerine göre değerlendirmenize izin vererek). Bunları, ünite testlerinde çok az kullanmaya çalışırdım, çünkü onları kullanarak, aslında işlev uygulamasını test etmeye çalışırsınız, arayüzüne uyumu değil, ama yine de kullanımları vardır. İhtiyaç duyduğunuz sahtekarlığı yaratmanıza yardımcı olmak için pek çok sahte çerçeve vardır.
Bu yöntemlerden herhangi biri bir hata atarsa, hatanın uygun gördüğü şekliyle işleyebilmesi için çağrının koduna kabarmasını istiyoruz. API kodu tarafından çağrılıyorsa, hatayı uygun bir HTTP yanıt koduna çevirebilir. Bir web arayüzü tarafından aranıyorsa, hatayı kullanıcıya gösterilecek şekilde uygun bir mesaja çevirebilir. Mesele şu ki, bu fonksiyon atılabilecek hataları nasıl idare edeceğini bilmiyor.
Beklenen istisnalar / hatalar geçerli test durumlarıdır: Böyle bir olay olması durumunda, işlevin beklediğiniz gibi davrandığını onaylarsınız. Bu, ilgili sahte / sahte / saplama nesnesinin istendiğinde atmasını sağlayarak başarılabilir.
Kafamın özü, böyle bir işlevi test etmek için testin kendisinde tam olarak uygulamanın tekrarlanmasının gerekli göründüğüdür (yöntemlerin belli bir sıradaki alaylara çağrılmasıyla) ve bu yanlış görünüyor.
Bazen bu yapılmalı (entegrasyon testlerinde çoğunlukla bunu umursuyorsanız da). Daha sık, beklenen yan etkileri / durum değişikliklerini doğrulamanın başka yolları da vardır.
Tam işlev çağrılarının doğrulanması, oldukça kırılgan birim testlerinin yapılmasını sağlar: Orijinal işlevde yalnızca küçük değişiklikler yapılmamasına neden olur. Bu arzu edilebilir veya istenmeyebilir, ancak bir işlevi değiştirdiğinizde ilgili birim test (ler) inde bir değişiklik yapılması gerekir (yeniden düzenleme, optimizasyon, hata düzeltme, ...).
Ne yazık ki, bu durumda ünite testi bazı güvenilirliğini kaybeder: değiştiğinden, değişiklik eskisi gibi davrandıktan sonra işlevi onaylamaz.
Örneğin, oven.preheat()
çerez pişirme örneğinizde (optimizasyon!) Bir arama ekleyen birini düşünün :
- Fırın nesnesini alay ettiyseniz, yöntemin gözlemlenebilir davranışı değişmediyse de denemenin başarısız olduğunu beklemez ve testin başarısız olmasını beklemez (umarım hala bir kurabiye tabağınız vardır).
- Bir saplama, yalnızca test edilecek yöntemleri veya tüm arayüzü bazı kukla yöntemlerle eklediğinize bağlı olarak başarısız olabilir veya olmayabilir.
- Sahte başarısız olmalı, çünkü yöntemi uygulamalıdır (arayüze göre)
Birim testlerimde mümkün olduğunca genel olmaya çalışıyorum: Uygulama değişirse, ancak görünen davranış (arayanın perspektifinden) hala aynıysa, testlerim geçmelidir. İdeal olarak, mevcut bir ünite testini değiştirmem gereken tek vaka bir hata düzeltmesi olmalıdır (testin değil, test edilen fonksiyonun).