Closed mihaela0608 closed 3 months ago
Здравей!
Доколкото виждам и разбирам, проблемът се състои в това че използваш REST client извиквания във функционалности, които искаш да тестваш. Те съвсем естествено гърмят, защото другия проект не съществува по време на тестове. Например, при регистрацията - викаш външния сървиз.
Оттук нататък опциите са много разнообразни. Като първа стъпка, тъй като RestClient API-то е твърде трудно за mock-ване (както виждам си забелязала) може да изкараш цялата комуникация в отделен интеграционен сървис който да енкапсулира REST Client-a. Например, вместо:
private void addLastMonthProfile(User user) {
UserData userData = new UserData(user.getId());
userData.setLastMonthSavings(BigDecimal.ZERO);
userData.setLastMonthExpenses(BigDecimal.ZERO);
restClient.post()
.uri("http://localhost:8081/api/userdata")
.body(userData)
.retrieve();
}
да бъде:
private void addLastMonthProfile(User user) {
UserData userData = new UserData(user.getId());
userData.setLastMonthSavings(BigDecimal.ZERO);
userData.setLastMonthExpenses(BigDecimal.ZERO);
userDataService.saveUserData(userData);
}
И вътре в userDataService
да си работиш с restClient
-a. Така вместо да се пробваш да мокнеш restClient
(което е трудно) може да мокваш userDataService
(което е лесно).
Оттам нататък имаш различни опции:
@SpringBootTest <--- това е за integration test-ове
@ExtendWith(MockitoExtension.class) <---- това е за unit тестове
Двете заедно - тц. Може би така става:
@SpringBootTest
class TrackItApplicationTests {
@MockBean // това е мок, който се слага в AppicationContext-a на мястото на истинския бийн.
private RestClient restClient;
@Mock
private RestClient.RequestBodyUriSpec requestBodyUriSpec;// това е най обикновен, мок, нищо не прави, никъде не се слага за сега
@Mock
private RestClient.RequestHeadersSpec<?> requestHeadersSpec;
Т.е. mockbean замества истински бийн в application context-a
Можеш да си направиш още един @Primary
бийн в тестовите класове, който да замести истинския в контекста :-)
Можеш да мокнеш целия външен сървис с wiremock. Виж как го направихме тук.
Поздрави, Л.
BTW, за справка - изпращането на REST заявка по време на ДБ транзакция е голям проблем в практиката. :-) Защо?
Защото имаш няколко варианта как да стане това:
1.
Начало на транзакция. REST заявка. Край на транзакция.
Проблем - REST заявката може да мине, но транзакцията да фейлне.
2.
REST заявка. Начало на транзакция. Край на транзакция.
Проблем - REST заявката може да мине, но транзакцията да фейлне.
3.
Начало на транзакция. Край на транзакция. REST заявка.
Проблем - транзакцията може да мине, но REST заявката може да фейлне.
:-) По нормален начин няма как да го решиш, затова има един патърн който се нарича Transactional outbox.
В рамките на транзакцията записваш каквото е необходимо - например юзъра. В outbox таблица в същата транзакция записваш какво трябва да се прати по рест. Асинхронно, например с schduler изпращаш по рест каквото е необходимо, с необходимите retry механизми и т.н.
Поздрави, Л.
Много благодаря за помощта. Наистина опитах толкова начини за мокването на рест клиента и не се получаваше. Благодаря Ви много!
На ср, 24.07.2024 г., 19:40 ч. Lachezar Balev @.***> написа:
BTW, за справка - изпращането на REST заявка по време на ДБ транзакция е голям проблем в практиката. :-) Защо?
Защото имаш няколко варианта как да стане това:
1.
Начало на транзакция. REST заявка. Край на транзакция.
Проблем - REST заявката може да мине, но транзакцията да фейлне.
2.
REST заявка. Начало на транзакция. Край на транзакция.
Проблем - REST заявката може да мине, но транзакцията да фейлне.
3.
Начало на транзакция. Край на транзакция. REST заявка.
Проблем - транзакцията може да мине, но REST заявката може да фейлне.
:-) По нормален начин няма как да го решиш, затова има един патърн който се нарича Transactional outbox.
outbox.png (view on web) https://github.com/user-attachments/assets/c4421473-f2a6-4875-b421-a947bb273a7a
В рамките на транзакцията записваш каквото е необходимо - например юзъра. В outbox таблица в същата транзакция записваш какво трябва да се прати по рест. Асинхронно, например с schduler изпращаш по рест каквото е необходимо, с необходимите retry механизми и т.н.
Поздрави, Л.
— Reply to this email directly, view it on GitHub https://github.com/luchob/softuni-spring-may-2024/issues/57#issuecomment-2248463479, or unsubscribe https://github.com/notifications/unsubscribe-auth/A74YTMUCJOSIJVDMNUOVAQDZN7KG5AVCNFSM6AAAAABLMZLUWSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENBYGQ3DGNBXHE . You are receiving this because you authored the thread.Message ID: @.***>
Връзка към проекта:(https://github.com/mihaela0608/TrackIt) Проблемът е с тестовете ми.
При стартиране на всички тестове, тестът за регистрация или тестът за contextLoads може да се види проблема.