En Yaygın 10 Spring Framework Hatası
Yayınlanan: 2022-03-11Spring, tartışmasız en popüler Java çerçevelerinden biridir ve aynı zamanda evcilleştirilmesi gereken güçlü bir canavardır. Temel kavramlarını kavramak oldukça kolay olsa da, güçlü bir Spring geliştiricisi olmak biraz zaman ve çaba gerektirir.
Bu makalede, özellikle web uygulamalarına ve Spring Boot'a yönelik, Spring'de daha yaygın olan bazı hataları ele alacağız. Spring Boot'un web sitesinde belirtildiği gibi, Spring Boot, üretime hazır uygulamaların nasıl oluşturulması gerektiği konusunda fikir sahibi bir görüş alıyor, bu nedenle bu makale bu görüşü taklit etmeye çalışacak ve standart Spring Boot web uygulaması geliştirmesine iyi bir şekilde dahil olacak bazı ipuçlarına genel bir bakış sunacak.
Spring Boot'a pek aşina değilseniz ama yine de bahsedilen şeylerden bazılarını denemek isterseniz, bu makaleye eşlik eden bir GitHub deposu oluşturdum. Makalenin herhangi bir noktasında kaybolmuş hissediyorsanız, depoyu klonlamanızı ve yerel makinenizdeki kodla oynamanızı tavsiye ederim.
Yaygın Hata 1: Çok Düşük Seviyeye Gitmek
Yazılım geliştirme dünyasında “burada icat edilmedi” sendromu oldukça yaygın olduğu için bu yaygın hatayla vuruyoruz. Yaygın olarak kullanılan kodun düzenli olarak yeniden yazılması ve birçok geliştiricinin bundan muzdarip olduğu belirtiler.
Belirli bir kitaplığın içindekileri ve onun uygulamasını anlamak çoğunlukla iyi ve gerekli olsa da (ve aynı zamanda harika bir öğrenme süreci olabilir), aynı düşük seviyeli uygulamayı sürekli olarak ele almak bir yazılım mühendisi olarak gelişiminiz için zararlıdır. detaylar. Spring gibi soyutlamaların ve çerçevelerin var olmasının bir nedeni vardır; bu, sizi tekrarlayan manuel çalışmalardan tam olarak ayırmak ve daha yüksek düzeyde ayrıntılara, etki alanı nesneleriniz ve iş mantığınıza konsantre olmanızı sağlar.
Bu yüzden soyutlamaları benimseyin - bir dahaki sefer belirli bir problemle karşılaştığınızda, önce hızlı bir arama yapın ve bu problemi çözen bir kütüphanenin halihazırda Spring'e entegre olup olmadığını belirleyin; günümüzde, uygun bir mevcut çözüm bulma şansınız var. Yararlı bir kitaplık örneği olarak, bu makalenin geri kalanında örneklerde Project Lombok ek açıklamalarını kullanacağım. Lombok, standart kod üreteci olarak kullanılır ve içinizdeki tembel geliştirici, umarız, kitaplığı tanımakta sorun yaşamaz. Örnek olarak, Lombok ile bir "standart Java çekirdeği"nin nasıl göründüğüne bakın:
@Getter @Setter @NoArgsConstructor public class Bean implements Serializable { int firstBeanProperty; String secondBeanProperty; }
Tahmin edebileceğiniz gibi, yukarıdaki kod şu şekilde derlenir:
public class Bean implements Serializable { private int firstBeanProperty; private String secondBeanProperty; public int getFirstBeanProperty() { return this.firstBeanProperty; } public String getSecondBeanProperty() { return this.secondBeanProperty; } public void setFirstBeanProperty(int firstBeanProperty) { this.firstBeanProperty = firstBeanProperty; } public void setSecondBeanProperty(String secondBeanProperty) { this.secondBeanProperty = secondBeanProperty; } public Bean() { } }
Ancak, Lombok'u IDE'nizle kullanmayı düşünüyorsanız, büyük olasılıkla bir eklenti yüklemeniz gerekeceğini unutmayın. Eklentinin IntelliJ IDEA sürümü burada bulunabilir.
Yaygın Hata #2: 'Sızdıran' İç Parçalar
Dahili yapınızı ortaya çıkarmak hiçbir zaman iyi bir fikir değildir çünkü hizmet tasarımında esneklik yaratmaz ve sonuç olarak kötü kodlama uygulamalarını teşvik eder. 'Sızdıran' dahili bilgiler, veritabanı yapısını belirli API uç noktalarından erişilebilir hale getirerek kendini gösterir. Örnek olarak, aşağıdaki POJO'nun (“Düz Eski Java Nesnesi”) veritabanınızdaki bir tabloyu temsil ettiğini varsayalım:
@Entity @NoArgsConstructor @Getter public class TopTalentEntity { @Id @GeneratedValue private Integer id; @Column private String name; public TopTalentEntity(String name) { this.name = name; } }
Diyelim ki TopTalentEntity
verilerine erişmesi gereken bir uç nokta var. TopTalentEntity
örneklerini döndürmek cazip gelse de, API uç noktasında TopTalentEntity
verilerini temsil etmek için yeni bir sınıf oluşturmak daha esnek bir çözüm olabilir:
@AllArgsConstructor @NoArgsConstructor @Getter public class TopTalentData { private String name; }
Bu şekilde, veritabanınızın arka ucunda değişiklik yapmak, hizmet katmanında herhangi bir ek değişiklik gerektirmez. Kullanıcılarınızın parola karmalarını veritabanında depolamak için TopTalentEntity
bir 'parola' alanı eklemeniz durumunda ne olacağını düşünün - TopTalentData
gibi bir bağlayıcı olmadan, hizmet ön ucunu değiştirmeyi unutmak, yanlışlıkla çok istenmeyen bazı gizli bilgileri açığa çıkarır. !
Yaygın Hata #3: Endişelerin Ayrılmaması
Uygulamanız büyüdükçe, kod organizasyonu giderek daha önemli bir konu olmaya başlar. İronik olarak, iyi yazılım mühendisliği ilkelerinin çoğu, özellikle uygulama mimarisi tasarımına fazla düşünülmediği durumlarda, ölçekte bozulmaya başlar. Geliştiricilerin o zaman yenik düşmeye meyilli olduğu en yaygın hatalardan biri, kod endişelerini karıştırmaktır ve bunu yapmak son derece kolaydır!
Endişelerin ayrılmasını genellikle bozan şey, yeni işlevleri mevcut sınıflara 'dökmektir'. Bu, elbette, kısa vadeli harika bir çözümdür (yeni başlayanlar için, daha az yazma gerektirir), ancak ister test, bakım veya arada bir yerde olsun, kaçınılmaz olarak yolun ilerisinde bir sorun haline gelir. TopTalentData
deposundan döndüren aşağıdaki denetleyiciyi göz önünde bulundurun:
@RestController public class TopTalentController { private final TopTalentRepository topTalentRepository; @RequestMapping("/toptal/get") public List<TopTalentData> getTopTalent() { return topTalentRepository.findAll() .stream() .map(this::entityToData) .collect(Collectors.toList()); } private TopTalentData entityToData(TopTalentEntity topTalentEntity) { return new TopTalentData(topTalentEntity.getName()); } }
İlk başta, bu kod parçasında özellikle yanlış bir şey yokmuş gibi görünebilir; TopTalentEntity
örneklerinden alınan bir TopTalentData
listesi sağlar. Ancak daha yakından baktığımızda, aslında TopTalentController
burada gerçekleştirdiği birkaç şey olduğunu görebiliriz; yani, istekleri belirli bir uç noktaya eşliyor, bir havuzdan veri alıyor ve TopTalentRepository
alınan varlıkları farklı bir formata dönüştürüyor. 'Daha temiz' bir çözüm, bu endişeleri kendi sınıflarına ayırmak olacaktır. Bunun gibi görünebilir:
@RestController @RequestMapping("/toptal") @AllArgsConstructor public class TopTalentController { private final TopTalentService topTalentService; @RequestMapping("/get") public List<TopTalentData> getTopTalent() { return topTalentService.getTopTalent(); } } @AllArgsConstructor @Service public class TopTalentService { private final TopTalentRepository topTalentRepository; private final TopTalentEntityConverter topTalentEntityConverter; public List<TopTalentData> getTopTalent() { return topTalentRepository.findAll() .stream() .map(topTalentEntityConverter::toResponse) .collect(Collectors.toList()); } } @Component public class TopTalentEntityConverter { public TopTalentData toResponse(TopTalentEntity topTalentEntity) { return new TopTalentData(topTalentEntity.getName()); } }
Bu hiyerarşinin ek bir avantajı, yalnızca sınıf adını inceleyerek işlevselliğin nerede olduğunu belirlememize izin vermesidir. Ayrıca, test sırasında, ihtiyaç duyulursa, sınıflardan herhangi birini sahte bir uygulama ile kolayca değiştirebiliriz.
Yaygın Hata #4: Tutarsızlık ve Kötü Hata İşleme
Tutarlılık konusu mutlaka Spring'e (veya bu konuda Java'ya) özel değildir, ancak yine de Spring projeleri üzerinde çalışırken dikkate alınması gereken önemli bir husustur. Kodlama stili tartışmaya açık olabilir (ve genellikle bir ekip içinde veya tüm şirket içinde bir anlaşma meselesidir), ortak bir standarda sahip olmak büyük bir üretkenlik yardımı olarak ortaya çıkıyor. Bu, özellikle çok kişilik ekipler için geçerlidir; Tutarlılık, elde tutma için çok fazla kaynak harcanmadan veya farklı sınıfların sorumluluklarına ilişkin uzun açıklamalar sağlamadan el değiştirmenin gerçekleşmesine izin verir.
Çeşitli yapılandırma dosyaları, hizmetleri ve denetleyicileri ile bir Spring projesi düşünün. Adlandırmada anlamsal olarak tutarlı olmak, herhangi bir yeni geliştiricinin kodda kendi yolunu yönetebileceği, kolayca aranabilir bir yapı oluşturur; Örneğin, yapılandırma sınıflarınıza Yapılandırma son ekleri, hizmetlerinize Hizmet son ekleri ve denetleyicilerinize Denetleyici son ekleri ekleme.
Tutarlılık konusuyla yakından ilgili olarak, sunucu tarafında hata işleme özel bir vurguyu hak ediyor. Kötü yazılmış bir API'den gelen istisna yanıtlarını ele almak zorunda kaldıysanız, muhtemelen nedenini biliyorsunuzdur – istisnaları düzgün bir şekilde ayrıştırmak zahmetli olabilir ve bu istisnaların ilk etapta neden meydana geldiğinin nedenini belirlemek daha da acı verici olabilir.
Bir API geliştiricisi olarak, ideal olarak, kullanıcıya yönelik tüm uç noktaları kapsamak ve bunları ortak bir hata biçimine dönüştürmek istersiniz. Bu genellikle, a) bir “500 Dahili Sunucu Hatası” mesajı döndürmek veya b) yığın izini yalnızca kullanıcıya atmak (aslında her ne pahasına olursa olsun kaçınılması gereken) gibi bir kopukluk çözümü yerine genel bir hata koduna ve açıklamasına sahip olmak anlamına gelir. istemci tarafını ele almanın zor olmasının yanı sıra içlerinizi ortaya çıkardığı için).
Yaygın bir hata yanıtı biçiminin bir örneği şunlar olabilir:
@Value public class ErrorResponse { private Integer errorCode; private String errorMessage; }
Buna benzer bir şeye çoğu popüler API'de yaygın olarak rastlanır ve kolayca ve sistematik olarak belgelenebildiği için iyi çalışma eğilimindedir. İstisnaları bu biçime çevirmek, bir yönteme @ExceptionHandler
ek açıklaması sağlanarak yapılabilir (bir açıklama örneği Ortak Hata #6'dadır).
Yaygın Hata #5: Çoklu İş Parçacığıyla Uygunsuz Şekilde Başa Çıkmak
İster masaüstü ister web uygulamalarında karşılaşılsın, Spring olsun veya olmasın, çoklu iş parçacığı, kırılması zor bir somun olabilir. Programların paralel yürütülmesinden kaynaklanan sorunlar sinir bozucu bir şekilde anlaşılması güçtür ve çoğu zaman hata ayıklaması son derece zordur - aslında, sorunun doğası gereği, bir paralel yürütme sorunuyla uğraştığınızı fark ettiğinizde, muhtemelen hata ayıklayıcıdan tamamen vazgeçmeniz ve kök hata nedenini bulana kadar kodunuzu "elle" incelemeniz gerekir. Ne yazık ki, bu tür sorunları çözmek için bir çerez kesici çözümü mevcut değildir; özel durumunuza bağlı olarak, durumu değerlendirmeniz ve ardından soruna en iyi olduğunu düşündüğünüz açıdan saldırmanız gerekecek.
İdeal olarak, elbette, çoklu kullanım hatalarından tamamen kaçınmak istersiniz. Yine, bunu yapmak için herkese uyan tek bir yaklaşım mevcut değildir, ancak hata ayıklama ve çoklu iş parçacığı hatalarını önlemeye yönelik bazı pratik hususlar şunlardır:
Küresel Durumdan Kaçının
Birincisi, her zaman “küresel devlet” meselesini hatırlayın. Çok iş parçacıklı bir uygulama oluşturuyorsanız, kesinlikle küresel olarak değiştirilebilen her şey yakından izlenmeli ve mümkünse tamamen kaldırılmalıdır. Genel değişkenin değiştirilebilir kalması için bir neden varsa, senkronizasyonu dikkatli bir şekilde uygulayın ve yeni tanıtılan bekleme süreleri nedeniyle yavaşlamadığını doğrulamak için uygulamanızın performansını izleyin.
Değişkenlikten Kaçının
Bu, doğrudan işlevsel programlamadan gelir ve OOP'ye uyarlanmış, sınıf değişkenliğinden ve değişen durumdan kaçınılması gerektiğini belirtir. Bu, kısaca, yukarıdaki setter yöntemleri ve tüm model sınıflarınızda özel final alanlarına sahip olmak anlamına gelir. Değerlerinin mutasyona uğradığı tek zaman inşaat sırasındadır. Bu şekilde, hiçbir çekişme sorununun ortaya çıkmadığından ve nesne özelliklerine erişmenin her zaman doğru değerleri sağlayacağından emin olabilirsiniz.
Önemli Verileri Günlüğe Kaydet
Uygulamanızın nerede sorun yaratabileceğini değerlendirin ve tüm önemli verileri önceden günlüğe kaydedin. Bir hata oluşursa, hangi isteklerin alındığını belirten bilgilere sahip olduğunuz ve uygulamanızın neden hatalı davrandığını daha iyi anladığınız için minnettar olacaksınız. Günlüğe kaydetmenin ek dosya G/Ç'sini getirdiğini ve bu nedenle uygulamanızın performansını ciddi şekilde etkileyebileceği için kötüye kullanılmaması gerektiğini tekrar belirtmek gerekir.

Mevcut Uygulamaları Yeniden Kullanın
Kendi iş parçacıklarınızı oluşturmaya ihtiyaç duyduğunuzda (örneğin, farklı hizmetlere zaman uyumsuz isteklerde bulunmak için), kendi çözümlerinizi oluşturmak yerine mevcut güvenli uygulamaları yeniden kullanın. Bu, çoğunlukla, iş parçacığı oluşturma için ExecutorServices ve Java 8'in düzgün işlevsel stili CompletableFutures'ın kullanılması anlamına gelir. Spring ayrıca, DeferredResult sınıfı aracılığıyla eşzamansız istek işlemeye de izin verir.
Yaygın Hata #6: Açıklama Tabanlı Doğrulama Kullanmamak
Daha önceki TopTalent hizmetimizin yeni En İyi Yetenekler eklemek için bir uç nokta gerektirdiğini düşünelim. Ayrıca, gerçekten geçerli bir nedenle, her yeni adın tam olarak 10 karakter uzunluğunda olması gerektiğini söyleyelim. Bunu yapmanın bir yolu şu olabilir:
@RequestMapping("/put") public void addTopTalent(@RequestBody TopTalentData topTalentData) { boolean nameNonExistentOrHasInvalidLength = Optional.ofNullable(topTalentData) .map(TopTalentData::getName) .map(name -> name.length() == 10) .orElse(true); if (nameNonExistentOrInvalidLength) { // throw some exception } topTalentService.addTopTalent(topTalentData); }
Bununla birlikte, yukarıdakiler (kötü inşa edilmiş olmanın yanı sıra) gerçekten 'temiz' bir çözüm değildir. Birden fazla geçerlilik türü (yani, TopTalentData
boş olmadığını ve TopTalentData.name
boş olmadığını ve TopTalentData.name
10 karakter uzunluğunda olduğunu) kontrol ediyoruz ve ayrıca veriler geçersizse bir istisna atıyoruz. .
Bu, Spring ile Hibernate validator kullanılarak çok daha temiz bir şekilde yürütülebilir. Doğrulamayı desteklemek için önce addTopTalent
yöntemini yeniden düzenleyelim:
@RequestMapping("/put") public void addTopTalent(@Valid @NotNull @RequestBody TopTalentData topTalentData) { topTalentService.addTopTalent(topTalentData); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleInvalidTopTalentDataException(MethodArgumentNotValidException methodArgumentNotValidException) { // handle validation exception }
Ek olarak, TopTalentData
sınıfında hangi özelliği doğrulamak istediğimizi belirtmemiz gerekecek:
public class TopTalentData { @Length(min = 10, max = 10) @NotNull private String name; }
Şimdi Spring, isteğe müdahale edecek ve yöntem çağrılmadan önce onu doğrulayacaktır - ek manuel testler kullanmaya gerek yoktur.
Aynı şeyi başarabilmemizin bir başka yolu da kendi açıklamalarımızı oluşturmaktır. Genellikle özel açıklamaları yalnızca ihtiyaçlarınız Hazırda Bekletme'nin yerleşik kısıtlama kümesini aştığında kullanacak olsanız da, bu örnekte @Length yokmuş gibi davranalım. Biri doğrulama ve diğeri açıklama ekleme için olmak üzere iki ek sınıf oluşturarak dize uzunluğunu kontrol eden bir doğrulayıcı yaparsınız:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = { MyAnnotationValidator.class }) public @interface MyAnnotation { String message() default "String length does not match expected"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; int value(); } @Component public class MyAnnotationValidator implements ConstraintValidator<MyAnnotation, String> { private int expectedLength; @Override public void initialize(MyAnnotation myAnnotation) { this.expectedLength = myAnnotation.value(); } @Override public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { return s == null || s.length() == this.expectedLength; } }
Bu durumlarda, endişelerin ayrılmasına ilişkin en iyi uygulamaların, bir özelliği null ( isValid
yönteminde s == null
) olması durumunda geçerli olarak işaretlemenizi ve ardından bu ek bir gereklilikse bir @NotNull
notu kullanmanızı gerektirdiğini unutmayın. Emlak:
public class TopTalentData { @MyAnnotation(value = 10) @NotNull private String name; }
Yaygın Hata #7: (Hala) XML Tabanlı Bir Yapılandırma Kullanma
Spring'in önceki sürümleri için XML bir gereklilik iken, günümüzde konfigürasyonun çoğu sadece Java kodu / ek açıklamaları aracılığıyla yapılabilir; XML yapılandırmaları, yalnızca ek ve gereksiz ortak kod olarak ortaya çıkar.
Bu makale (ve beraberindeki GitHub deposu), Spring'i yapılandırmak için ek açıklamalar kullanır ve Spring, kök paketine aşağıdaki gibi bir @SpringBootApplication
bileşik ek açıklaması eklendiğinden, hangi fasulyelerin bağlanması gerektiğini bilir:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Bileşik açıklama (Bunun hakkında daha fazla bilgiyi Spring belgelerinde bulabilirsiniz) Spring'e fasulye almak için hangi paketlerin taranması gerektiğine dair bir ipucu verir. Somut durumumuzda bu, aşağıdaki (co.kukurin) paketin kullanılacağı anlamına gelir. kablolama için:
-
@Component
(TopTalentConverter
,MyAnnotationValidator
) -
@RestController
(TopTalentController
) -
@Repository
(TopTalentRepository
) -
@Service
(TopTalentService
) sınıfları
@Configuration
açıklamalı ek sınıflarımız olsaydı, bunlar da Java tabanlı yapılandırma için kontrol edilirdi.
Yaygın Hata #8: Profilleri Unutmak
Sunucu geliştirmede sıklıkla karşılaşılan bir sorun, genellikle üretim ve geliştirme yapılandırmalarınız olmak üzere farklı yapılandırma türleri arasında ayrım yapmaktır. Testten uygulamanızı dağıtmaya her geçişinizde çeşitli yapılandırma girişlerini manuel olarak değiştirmek yerine, profilleri kullanmak daha verimli bir yol olacaktır.
Üretimde bir MySQL veritabanı ile yerel geliştirme için bir bellek içi veritabanı kullandığınız durumu düşünün. Bu, özünde, her ikisine de erişmek için farklı bir URL ve (umarız) farklı kimlik bilgileri kullanacağınız anlamına gelir. Bunun iki farklı yapılandırma dosyasıyla nasıl yapılabileceğini görelim:
application.yaml dosyası
# set default profile to 'dev' spring.profiles.active: dev # production database details spring.datasource.url: 'jdbc:mysql://localhost:3306/toptal' spring.datasource.username: root spring.datasource.password:
application-dev.yaml dosyası
spring.datasource.url: 'jdbc:h2:mem:' spring.datasource.platform: h2
Muhtemelen kodla uğraşırken üretim veritabanınızda yanlışlıkla herhangi bir işlem yapmak istemezsiniz, bu nedenle varsayılan profili dev olarak ayarlamak mantıklıdır. Sunucuda, JVM'ye bir -Dspring.profiles.active=prod
parametresi sağlayarak yapılandırma profilini manuel olarak geçersiz kılabilirsiniz. Alternatif olarak, işletim sisteminizin ortam değişkenini istediğiniz varsayılan profile ayarlayabilirsiniz.
Yaygın Hata #9: Bağımlılık Enjeksiyonunu Kucaklamama
Spring ile bağımlılık enjeksiyonunu doğru şekilde kullanmak, istenen tüm konfigürasyon sınıflarını tarayarak tüm nesnelerinizi birbirine bağlamasına izin vermek anlamına gelir; bu, ilişkileri ayırmak için faydalı olduğunu kanıtlıyor ve ayrıca test etmeyi çok daha kolay hale getiriyor. Bunun gibi bir şey yaparak sıkı bağlantı sınıfları yerine:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController() { this.topTalentService = new TopTalentService(); } }
Spring'in bizim için kablolamayı yapmasına izin veriyoruz:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController(TopTalentService topTalentService) { this.topTalentService = topTalentService; } }
Misko Hevery'nin Google konuşması, bağımlılık enjeksiyonunun 'nedenlerini' derinlemesine açıklıyor, onun yerine pratikte nasıl kullanıldığını görelim. Endişelerin ayrılmasıyla ilgili bölümde (Genel Hatalar #3) bir hizmet ve denetleyici sınıfı oluşturduk. TopTalentService
doğru davrandığı varsayımı altında denetleyiciyi test etmek istediğimizi varsayalım. Ayrı bir yapılandırma sınıfı sağlayarak gerçek hizmet uygulamasının yerine sahte bir nesne ekleyebiliriz:
@Configuration public class SampleUnitTestConfig { @Bean public TopTalentService topTalentService() { TopTalentService topTalentService = Mockito.mock(TopTalentService.class); Mockito.when(topTalentService.getTopTalent()).thenReturn( Stream.of("Mary", "Joel").map(TopTalentData::new).collect(Collectors.toList())); return topTalentService; } }
Ardından, Spring'e yapılandırma tedarikçisi olarak SampleUnitTestConfig
kullanmasını söyleyerek sahte nesneyi enjekte edebiliriz:
@ContextConfiguration(classes = { SampleUnitTestConfig.class })
Bu, özel çekirdeği bir birim testine enjekte etmek için bağlam yapılandırmasını kullanmamıza izin verir.
Yaygın Hata #10: Test Eksikliği veya Uygunsuz Test
Birim testi fikri uzun süredir bizimle olsa da, birçok geliştirici bunu yapmayı “unutuyor” (özellikle gerekli değilse) ya da sonradan eklemeyi düşünüyor. Testler yalnızca kodunuzun doğruluğunu doğrulamakla kalmamalı, aynı zamanda uygulamanın farklı durumlarda nasıl davranması gerektiğine dair belgeler olarak da hizmet etmesi gerektiğinden, bu açıkça istenmez.
HTTP üzerinden iletişim genellikle Spring'in DispatcherServlet
çağırmanızı ve gerçek bir HttpServletRequest
alındığında ne olduğunu görmenizi gerektirdiğinden (bunu bir entegrasyon testi yaparak, doğrulama, serileştirme ile uğraşarak) web servislerini test ederken, nadiren yalnızca 'saf' birim testleri yaparsınız. , vb). MockMVC'nin yanı sıra REST hizmetlerinin kolay test edilmesi için bir Java DSL olan REST Assured'ın çok zarif bir çözüm sunduğu kanıtlanmıştır. Bağımlılık ekleme ile aşağıdaki kod parçacığını göz önünde bulundurun:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { Application.class, SampleUnitTestConfig.class }) public class RestAssuredTestDemonstration { @Autowired private TopTalentController topTalentController; @Test public void shouldGetMaryAndJoel() throws Exception { // given MockMvcRequestSpecification givenRestAssuredSpecification = RestAssuredMockMvc.given() .standaloneSetup(topTalentController); // when MockMvcResponse response = givenRestAssuredSpecification.when().get("/toptal/get"); // then response.then().statusCode(200); response.then().body("name", hasItems("Mary", "Joel")); } }
SampleUnitTestConfig
, TopTalentService'in sahte bir uygulamasını TopTalentService
bağlarken, diğer tüm sınıflar, Uygulama sınıfı paketinde TopTalentController
tarama paketlerinden çıkarılan standart yapılandırma kullanılarak bağlanır. RestAssuredMockMvc
, basit bir ortam oluşturmak ve /toptal/get
uç noktasına bir GET
isteği göndermek için kullanılır.
Bahar Ustası Olmak
Spring, başlaması kolay, ancak tam ustalığa ulaşmak için biraz özveri ve zaman gerektiren güçlü bir çerçevedir. Çerçeveyi tanımak için zaman ayırmanız, uzun vadede üretkenliğinizi kesinlikle artıracak ve nihayetinde daha temiz kod yazmanıza ve daha iyi bir geliştirici olmanıza yardımcı olacaktır.
Daha fazla kaynak arıyorsanız, Spring In Action, birçok temel Spring konusunu kapsayan iyi bir uygulamalı kitaptır.