paint-brush
Etkili Entegrasyon Testleri Oluşturma: Bahar Çerçevesindeki En İyi Uygulamalar ve Araçlarile@avvero
531 okumalar
531 okumalar

Etkili Entegrasyon Testleri Oluşturma: Bahar Çerçevesindeki En İyi Uygulamalar ve Araçlar

ile Anton Belyaev8m2024/05/26
Read on Terminal Reader

Çok uzun; Okumak

Bu makale, entegrasyon testleri yazmaya yönelik pratik öneriler sunmakta, harici hizmetlerle etkileşimlerin özelliklerine nasıl odaklanılacağını göstererek testleri daha okunaklı ve bakımı kolay hale getirmektedir. Bu yaklaşım yalnızca testin verimliliğini artırmakla kalmıyor, aynı zamanda uygulama içindeki entegrasyon süreçlerinin daha iyi anlaşılmasını da sağlıyor. Belirli örneklerin merceğinden, DSL paketleyicileri, JsonAssert ve Pact gibi çeşitli stratejiler ve araçlar incelenecek ve okuyucuya entegrasyon testlerinin kalitesini ve görünürlüğünü artırmaya yönelik kapsamlı bir kılavuz sunulacak.
featured image - Etkili Entegrasyon Testleri Oluşturma: Bahar Çerçevesindeki En İyi Uygulamalar ve Araçlar
Anton Belyaev HackerNoon profile picture
0-item

Modern yazılım geliştirmede etkili testler, uygulamaların güvenilirliğinin ve kararlılığının sağlanmasında önemli bir rol oynar.


Bu makale, entegrasyon testleri yazmaya yönelik pratik öneriler sunmakta, dış hizmetlerle etkileşimlerin özelliklerine nasıl odaklanılacağını göstererek testleri daha okunaklı ve bakımı kolay hale getirmektedir. Bu yaklaşım yalnızca testin verimliliğini artırmakla kalmıyor, aynı zamanda uygulama içindeki entegrasyon süreçlerinin daha iyi anlaşılmasını da sağlıyor. Belirli örneklerin merceğinden, DSL paketleyicileri, JsonAssert ve Pact gibi çeşitli stratejiler ve araçlar incelenecek ve okuyucuya entegrasyon testlerinin kalitesini ve görünürlüğünü artırmaya yönelik kapsamlı bir kılavuz sunulacak.


Makale, Spring uygulamalarındaki HTTP etkileşimlerini test etmek için Groovy'deki Spock Framework kullanılarak gerçekleştirilen entegrasyon testlerinin örneklerini sunmaktadır. Aynı zamanda önerilen temel teknikler ve yaklaşımlar, HTTP'nin ötesindeki çeşitli etkileşim türlerine etkili bir şekilde uygulanabilir.

Sorun Açıklaması

Baharda Etkili Entegrasyon Testleri Yazma: HTTP İstek Alaycılığı için Organize Test Stratejileri başlıklı makale, her biri kendi özel rolünü yerine getiren farklı aşamalara net bir şekilde ayrılan testler yazma yaklaşımını açıklamaktadır. Bu tavsiyelere göre ama bir değil iki isteği alaya alarak bir test örneği anlatalım. Yasama aşaması (Yürütme) kısa olması açısından atlanacaktır (tam bir test örneği proje deposunda bulunabilir).

Sunulan kod koşullu olarak bölümlere ayrılmıştır: "Destekleyici Kod" (gri renkli) ve "Dış Etkileşimlerin Belirtimi" (mavi renkli). Destekleyici Kod, isteklerin ele geçirilmesi ve yanıtların taklit edilmesi de dahil olmak üzere test etmeye yönelik mekanizmalar ve yardımcı programlar içerir. Dış Etkileşimlerin Belirtimi, beklenen istekler ve yanıtlar da dahil olmak üzere sistemin test sırasında etkileşimde bulunması gereken harici hizmetlerle ilgili belirli verileri açıklar. Destekleyici Kod testin temelini oluştururken Spesifikasyon doğrudan test etmeye çalıştığımız sistemin iş mantığı ve ana işlevleriyle ilgilidir.


Spesifikasyon, kodun küçük bir bölümünü kaplar ancak testi anlamak için önemli bir değeri temsil eder; oysa daha büyük bir yer kaplayan Destekleyici Kod, daha az değer sunar ve her sahte bildirim için tekrarlanır. Kodun MockRestServiceServer ile kullanılması amaçlanmıştır. WireMock'taki örneğe baktığımızda aynı modeli görebiliriz: spesifikasyon neredeyse aynıdır ve Destek Kodu farklılık gösterir.


Bu makalenin amacı, spesifikasyona odaklanılacak ve Destekleyici Kodun ikinci planda kalacağı şekilde test yazmaya yönelik pratik öneriler sunmaktır.

Gösteri Senaryosu

Test senaryomuz için, istekleri OpenAI API'sine ileten ve yanıtları kullanıcılara geri gönderen varsayımsal bir Telegram botu öneriyorum.

Hizmetlerle etkileşime yönelik sözleşmeler, operasyonun ana mantığını vurgulamak için basitleştirilmiş bir şekilde açıklanmaktadır. Aşağıda uygulama mimarisini gösteren bir sıra diyagramı bulunmaktadır. Tasarımın sistem mimarisi perspektifinden sorular ortaya çıkarabileceğini anlıyorum, ancak lütfen buna anlayışla yaklaşın; buradaki asıl amaç, testlerde görünürlüğü artırmaya yönelik bir yaklaşım göstermektir.

Teklif

Bu makalede test yazmaya yönelik aşağıdaki pratik öneriler anlatılmaktadır:

  • Örneklerle çalışmak için DSL paketleyicilerinin kullanılması.
  • Sonuç doğrulaması için JsonAssert kullanımı.
  • Harici etkileşimlerin özelliklerinin JSON dosyalarında saklanması.
  • Pakt dosyalarının kullanımı.

Alay için DSL Sarmalayıcıları Kullanma

DSL sarmalayıcının kullanılması standart sahte kodun gizlenmesine olanak tanır ve spesifikasyonla çalışmak için basit bir arayüz sağlar. Önerilenin belirli bir DSL değil, uyguladığı genel bir yaklaşım olduğunu vurgulamak önemlidir. DSL kullanılarak düzeltilmiş bir test örneği aşağıda sunulmaktadır ( tam test metni ).

 setup: def openaiRequestCaptor = restExpectation.openai.completions(withSuccess("{...}")) def telegramRequestCaptor = restExpectation.telegram.sendMessage(withSuccess("{}")) when: ... then: openaiRequestCaptor.times == 1 telegramRequestCaptor.times == 1

Örneğin restExpectation.openai.completions yönteminin şu şekilde tanımlandığı yer:

 public interface OpenaiMock { /** * This method configures the mock request to the following URL: {@code https://api.openai.com/v1/chat/completions} */ RequestCaptor completions(DefaultResponseCreator responseCreator); }

Yöntem hakkında yorum yapmak, kod düzenleyicide yöntem adının üzerine gelindiğinde, alay edilecek URL'yi görmek de dahil olmak üzere yardım almanıza olanak tanır.

Önerilen uygulamada, sahte yanıtın beyanı, ResponseCreator örnekleri kullanılarak yapılır ve aşağıdakiler gibi özel örneklere izin verilir:

 public static ResponseCreator withResourceAccessException() { return (request) -> { throw new ResourceAccessException("Error"); }; }

Bir dizi yanıtın belirtildiği başarısız senaryolara yönelik örnek bir test aşağıda gösterilmektedir:

 import static org.springframework.http.HttpStatus.FORBIDDEN setup: def openaiRequestCaptor = restExpectation.openai.completions(openaiResponse) def telegramRequestCaptor = restExpectation.telegram.sendMessage(withSuccess("{}")) when: ... then: openaiRequestCaptor.times == 1 telegramRequestCaptor.times == 0 where: openaiResponse | _ withResourceAccessException() | _ withStatus(FORBIDDEN) | _

WireMock için yanıt oluşumunun biraz farklı olması dışında her şey aynıdır ( test kodu , yanıt fabrikası sınıf kodu ).

Daha İyi IDE Entegrasyonu için @Language("JSON") Ek Açıklamasını Kullanma

Bir DSL uygularken, IntelliJ IDEA'daki belirli kod parçacıkları için dil özelliği desteğini etkinleştirmek amacıyla yöntem parametrelerine @Language("JSON") ile açıklama eklemek mümkündür. Örneğin JSON'da editör, dize parametresini JSON kodu olarak ele alacak ve sözdizimi vurgulama, otomatik tamamlama, hata kontrolü, gezinme ve yapı arama gibi özellikleri etkinleştirecektir. Aşağıda ek açıklamanın kullanımına bir örnek verilmiştir:

 public static DefaultResponseCreator withSuccess(@Language("JSON") String body) { return MockRestResponseCreators.withSuccess(body, APPLICATION_JSON); }

Editörde şöyle görünüyor:

Sonuç Doğrulaması için JsonAssert'i Kullanma

JSONAssert kitaplığı, JSON yapılarının test edilmesini basitleştirmek için tasarlanmıştır. Çeşitli karşılaştırma modlarını destekleyerek geliştiricilerin beklenen ve gerçek JSON dizelerini yüksek düzeyde esneklikle kolayca karşılaştırmasına olanak tanır.

Bu, bunun gibi bir doğrulama açıklamasından geçişe olanak tanır

 openaiRequestCaptor.body.model == "gpt-3.5-turbo" openaiRequestCaptor.body.messages.size() == 1 openaiRequestCaptor.body.messages[0].role == "user" openaiRequestCaptor.body.messages[0].content == "Hello!"

böyle bir şeye

 assertEquals("""{ "model": "gpt-3.5-turbo", "messages": [{ "role": "user", "content": "Hello!" }] }""", openaiRequestCaptor.bodyString, false)

Bana göre ikinci yaklaşımın temel avantajı, çeşitli bağlamlarda (dokümantasyon, günlükler ve testlerde) veri temsili tutarlılığını sağlamasıdır. Bu, test sürecini önemli ölçüde basitleştirerek karşılaştırmada esneklik ve hata teşhisinde doğruluk sağlar. Böylece, testleri yazma ve sürdürmede zamandan tasarruf etmenin yanı sıra okunabilirliğini ve bilgilendiriciliğini de artırıyoruz.

Spring Boot içinde çalışırken, en az sürüm 2'den başlayarak, kitaplıkla çalışmak için hiçbir ek bağımlılığa gerek yoktur; çünkü org.springframework.boot:spring-boot-starter-test zaten org.skyscreamer:jsonassert bağımlılık içerir.

Dış Etkileşimlerin Belirtiminin JSON Dosyalarında Saklanması

Yapabileceğimiz bir gözlem, JSON dizelerinin testin önemli bir bölümünü kaplamasıdır. Saklanmaları mı gerekiyor? Evet ve hayır. Neyin daha fazla fayda sağladığını anlamak önemlidir. Bunları gizlemek testleri daha kompakt hale getirir ve testin özünü ilk bakışta kavramayı kolaylaştırır. Öte yandan, kapsamlı bir analiz için, harici etkileşimin spesifikasyonuna ilişkin önemli bilgilerin bir kısmı gizlenecek ve dosyalar arasında ekstra geçişler yapılması gerekecektir. Karar rahatlığa bağlıdır: sizin için daha rahat olanı yapın.

JSON dizelerini dosyalarda depolamayı seçerseniz, basit seçeneklerden biri yanıtları ve istekleri JSON dosyalarında ayrı ayrı tutmaktır. Aşağıda bir uygulama seçeneğini gösteren bir test kodu ( tam sürüm ) bulunmaktadır:

 setup: def openaiRequestCaptor = restExpectation.openai.completions(withSuccess(fromFile("json/openai/response.json"))) def telegramRequestCaptor = restExpectation.telegram.sendMessage(withSuccess("{}")) when: ... then: openaiRequestCaptor.times == 1 telegramRequestCaptor.times == 1

fromFile yöntemi basitçe src/test/resources dizinindeki bir dosyadan bir dize okur ve herhangi bir devrim niteliğinde fikir taşımaz ancak yine de referans için proje deposunda mevcuttur.

Dizenin değişken kısmı için org.Apache.commons.text.StringSubstitutor ile değiştirme kullanılması ve modeli açıklarken bir dizi değer iletilmesi önerilir, örneğin:

 setup: def openaiRequestCaptor = restExpectation.openai.completions(withSuccess(fromFile("json/openai/response.json", [content: "Hello! How can I assist you today?"])))

JSON dosyasında ikame edilen kısım şöyle görünür:

 ... "message": { "role": "assistant", "content": "${content:-Hello there, how may I assist you today?}" }, ...

Geliştiricilerin dosya depolama yaklaşımını benimserken karşılaştığı tek zorluk, test kaynaklarında uygun bir dosya yerleştirme şeması ve bir adlandırma şeması geliştirmektir. Bu dosyalarla çalışma deneyimini kötüleştirebilecek bir hata yapmak kolaydır. Bu soruna bir çözüm, daha sonra tartışılacak olan Pakt'taki spesifikasyonların kullanılması olabilir.

Groovy'de yazılan testlerde açıklanan yaklaşımı kullanırken sıkıntılarla karşılaşabilirsiniz: IntelliJ IDEA'da koddan dosyaya gitmek için destek yoktur, ancak bu işlevsellik için desteğin gelecekte eklenmesi beklenmektedir . Java'da yazılan testlerde bu harika çalışıyor.

Anlaşma Sözleşme Dosyalarını Kullanma

Terminolojiyle başlayalım.


Sözleşme testi, her uygulamanın gönderdiği veya aldığı mesajların bir "sözleşmede" belgelenen karşılıklı anlayışa uygunluğunu doğrulamak için ayrı ayrı test edildiği entegrasyon noktalarını test etme yöntemidir. Bu yaklaşım, sistemin farklı bölümleri arasındaki etkileşimlerin beklentileri karşılamasını sağlar.


Sözleşme testi bağlamında bir sözleşme, uygulamalar arasında alınıp verilen mesajların (talepler ve yanıtlar) formatı ve yapısı hakkındaki anlaşmayı kaydeden bir belge veya spesifikasyondur. Her uygulamanın, entegrasyon sırasında başkaları tarafından gönderilen ve alınan verileri doğru şekilde işleyebildiğini doğrulamak için temel görevi görür.


Sözleşme, bir tüketici (örneğin, bazı verileri almak isteyen bir müşteri) ile bir sağlayıcı (örneğin, müşterinin ihtiyaç duyduğu verileri sağlayan bir sunucudaki API) arasında kurulur.


Tüketici odaklı test, tüketicilerin otomatik test çalıştırmaları sırasında sözleşmeler oluşturduğu sözleşme testine yönelik bir yaklaşımdır. Bu sözleşmeler sağlayıcıya iletilir ve sağlayıcı daha sonra kendi otomatik testlerini yürütür. Sözleşme dosyasında yer alan her talep sağlayıcıya iletilir ve alınan yanıt, sözleşme dosyasında belirtilen beklenen yanıtla karşılaştırılır. Her iki yanıtın da eşleşmesi tüketici ile servis sağlayıcının uyumlu olduğu anlamına gelir.


Son olarak Pakt. Pact, tüketici odaklı sözleşme testi fikirlerini uygulayan bir araçtır. Kod öncelikli test geliştirmeye odaklanarak hem HTTP entegrasyonlarını hem de mesaj tabanlı entegrasyonları test etmeyi destekler.

Daha önce de belirttiğim gibi, görevimiz için Pakt'ın sözleşme özelliklerini ve araçlarını kullanabiliriz. Uygulama şu şekilde görünebilir ( tam test kodu ):

 setup: def openaiRequestCaptor = restExpectation.openai.completions(fromContract("openai/SuccessfulCompletion-Hello.json")) def telegramRequestCaptor = restExpectation.telegram.sendMessage(withSuccess("{}")) when: ... then: openaiRequestCaptor.times == 1 telegramRequestCaptor.times == 1

Sözleşme dosyası incelemeye açıktır .

Sözleşme dosyalarını kullanmanın avantajı, bunların yalnızca istek ve yanıt gövdesini değil aynı zamanda harici etkileşimler spesifikasyonunun diğer öğelerini (istek yolu, başlıklar ve HTTP yanıt durumu) içermesidir ve bu tür bir sözleşmeye dayalı olarak bir modelin tam olarak tanımlanmasına olanak tanır.

Bu durumda kendimizi sözleşmeli testlerle sınırladığımızı ve tüketici odaklı testleri genişletmediğimizi unutmamak önemlidir. Ancak birisi Pakt'ı daha detaylı incelemek isteyebilir.

Çözüm

Bu makalede, Bahar Çerçevesi ile geliştirme bağlamında entegrasyon testlerinin görünürlüğünü ve verimliliğini artırmaya yönelik pratik öneriler gözden geçirilmiştir. Amacım, dış etkileşimlerin özelliklerini açıkça tanımlamanın ve standart kodları en aza indirmenin önemine odaklanmaktı. Bu hedefe ulaşmak için DSL sarmalayıcıları ve JsonAssert'i kullanmayı, spesifikasyonları JSON dosyalarında saklamayı ve sözleşmelerle Pact aracılığıyla çalışmayı önerdim. Makalede açıklanan yaklaşımlar, test yazma ve sürdürme sürecini basitleştirmeyi, okunabilirliğini geliştirmeyi ve en önemlisi sistem bileşenleri arasındaki etkileşimleri doğru bir şekilde yansıtarak testin kalitesini artırmayı amaçlamaktadır.


Testleri gösteren proje havuzunun bağlantısı - sandbox/bot .


Makaleye gösterdiğiniz ilgi için teşekkür eder, etkili ve görünür testler yazma arayışınızda iyi şanslar dileriz!