{"id":70317,"date":"2024-07-22T07:12:41","date_gmt":"2024-07-22T03:42:41","guid":{"rendered":"https:\/\/nabfollower.com\/blog\/level-up-your-karate-testing-with-spring-boot-di-42em\/"},"modified":"2024-07-22T07:12:41","modified_gmt":"2024-07-22T03:42:41","slug":"level-up-your-karate-testing-with-spring-boot-di-42em","status":"publish","type":"post","link":"https:\/\/nabfollower.com\/blog\/level-up-your-karate-testing-with-spring-boot-di-42em\/","title":{"rendered":"\u062a\u0633\u062a \u06a9\u0627\u0631\u0627\u062a\u0647 \u062e\u0648\u062f \u0631\u0627 \u0628\u0627 Spring Boot DI \u0627\u0631\u062a\u0642\u0627 \u062f\u0647\u06cc\u062f"},"content":{"rendered":"<p>Summarize this content to 400 words in Persian Lang<br \/>\n            \u0686\u0646\u062f \u0633\u0627\u0644\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0645\u0646 \u0627\u0632 \u062e\u06cc\u0627\u0631 \u0628\u0631\u0627\u06cc \u062a\u0633\u062a \u0647\u0627\u06cc \u0633\u0637\u062d \u0628\u0627\u0644\u0627\u062a\u0631 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u06a9\u0646\u0645 \u0648 \u0627\u062e\u06cc\u0631\u0627\u064b \u06a9\u0627\u0631\u0627\u062a\u0647 \u0631\u0627 \u0634\u0631\u0648\u0639 \u06a9\u0631\u062f\u0647 \u0627\u0645.  \u062f\u0631 \u062d\u0627\u0644\u06cc \u06a9\u0647 \u062e\u06cc\u0627\u0631 \u06cc\u06a9 \u0627\u0628\u0632\u0627\u0631 \u0639\u0627\u0644\u06cc \u0627\u0633\u062a\u060c \u0645\u0646 \u0641\u06a9\u0631 \u0645\u06cc\u200c\u06a9\u0646\u0645 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0648\u0627\u0642\u0639\u0627\u064b \u062f\u0631 \u06a9\u0627\u0647\u0634 \u062d\u062c\u0645 \u062f\u06cc\u06af \u06a9\u0647 \u0647\u0645\u0631\u0627\u0647 \u0628\u0627 \u062a\u0639\u0627\u0631\u06cc\u0641 \u0645\u0631\u062d\u0644\u0647\u200c\u0627\u06cc \u0627\u0633\u062a \u0645\u06cc\u200c\u062f\u0631\u062e\u0634\u062f \u0648 \u0646\u0648\u0634\u062a\u0646 \u0633\u0631\u06cc\u0639 \u062a\u0633\u062a\u200c\u0647\u0627\u06cc \u0645\u0639\u0646\u06cc\u200c\u062f\u0627\u0631 \u0631\u0627 \u0622\u0633\u0627\u0646 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0645\u062e\u0635\u0648\u0635\u0627\u064b \u0648\u0642\u062a\u06cc \u0635\u062d\u0628\u062a \u0627\u0632 \u062a\u0633\u062a API \u0645\u06cc\u200c\u0634\u0648\u062f.<\/p>\n<p>\u0628\u0631\u0627\u06cc \u0628\u0631\u0646\u0627\u0645\u0647 \u0647\u0627\u06cc \u0633\u0627\u062f\u0647\u060c \u0646\u0648\u0634\u062a\u0646 \u0641\u0627\u06cc\u0644 \u0647\u0627\u06cc \u0648\u06cc\u0698\u06af\u06cc \u062e\u0648\u062f \u062f\u0631 \u062c\u0627\u0648\u0627 \u0627\u0633\u06a9\u0631\u06cc\u067e\u062a \u0633\u0627\u062f\u0647 \u06a9\u0627\u0641\u06cc \u0627\u0633\u062a.  \u0628\u0627 \u0631\u0634\u062f \u0628\u0631\u0646\u0627\u0645\u0647 \u0648 \u062a\u0633\u062a \u0647\u0627\u06cc \u0634\u0645\u0627\u060c \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u062c\u062f\u062f \u0627\u0632 \u0628\u0631\u062e\u06cc \u06a9\u062f\u0647\u0627\u06cc \u062c\u0627\u0648\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646\u062f \u0627\u0631\u0632\u0634\u0645\u0646\u062f \u0628\u0627\u0634\u062f.  API \u0647\u0627\u06cc Spring Boot \u0645\u06cc \u062a\u0648\u0627\u0646\u0646\u062f \u0627\u0632 \u062a\u0633\u062a \u06a9\u0627\u0631\u0627\u062a\u0647 \u0633\u0648\u062f \u0632\u06cc\u0627\u062f\u06cc \u0628\u0628\u0631\u0646\u062f\u060c \u0627\u0645\u0627 \u062f\u0631 \u0645\u0648\u0631\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0642\u062f\u0631\u062a Spring Boot \u0628\u0647 \u0637\u0648\u0631 \u0645\u0633\u062a\u0642\u06cc\u0645 \u062f\u0631 \u062a\u0633\u062a \u0647\u0627\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u0686\u0637\u0648\u0631\u061f<\/p>\n<p>\u0686\u0646\u062f \u0646\u0645\u0648\u0646\u0647 \u0627\u0632 \u0645\u0648\u0627\u0631\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647<\/p>\n<p>\u062f\u0631 \u062d\u0627\u0644\u06cc \u06a9\u0647 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0627\u0632 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0627\u0632 \u0637\u0631\u06cc\u0642 \u0641\u0627\u06cc\u0644\u200c\u0647\u0627\u06cc karate-config.js \u067e\u0634\u062a\u06cc\u0628\u0627\u0646\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0628\u0631\u062e\u06cc \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0628\u0647 \u062c\u0627\u06cc \u0622\u0646 \u0627\u0632 \u0637\u0631\u06cc\u0642 Spring YAML\/properties \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u06a9\u0646\u0646\u062f.  \u0627\u06cc\u0646 \u0645\u06cc \u062a\u0648\u0627\u0646\u062f \u0628\u0631\u0627\u06cc \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0645\u062c\u062f\u062f \u0645\u0648\u0627\u0631\u062f \u062e\u0627\u0631\u062c \u0627\u0632 \u06a9\u062f \u0628\u0627\u0632\u0633\u0627\u0632\u06cc \u0646\u06cc\u0632 \u0645\u0641\u06cc\u062f \u0628\u0627\u0634\u062f.<br \/>\n\u0628\u0631\u0627\u06cc \u0647\u0645\u06af\u0627\u0645\u200c\u0633\u0627\u0632\u06cc \u0628\u0631\u062e\u06cc \u0648\u06cc\u0698\u06af\u06cc\u200c\u0647\u0627\u06cc \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Spring Boot \u0628\u06cc\u0646 \u0628\u0631\u0646\u0627\u0645\u0647\u200c\u0647\u0627 \u0648 \u0622\u0632\u0645\u0627\u06cc\u0634\u200c\u0647\u0627.<br \/>\n\u0628\u0631\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0648\u0636\u0639\u06cc\u062a \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0628\u06cc\u0646 \u062a\u0645\u0627\u0633 \u0647\u0627\u06cc API.  \u0645\u062e\u0632\u0646 JPA\/\u062d\u0628\u0648\u0628\u0627\u062a \u0645\u0648\u062c\u0648\u062f\u06cc\u062a \u0631\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646 \u062f\u0631 \u0622\u0632\u0645\u0648\u0646 \u0647\u0627\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0631\u062f.<br \/>\n\u0628\u0631\u062e\u06cc \u0627\u0632 \u0644\u0648\u0628\u06cc\u0627\u0647\u0627\u06cc \u0628\u0647\u0627\u0631 \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0628\u0647 \u0633\u0627\u062f\u06af\u06cc \u0628\u0631\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u062f\u0631 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0647\u0627 \u0645\u0641\u06cc\u062f \u0628\u0627\u0634\u0646\u062f.<\/p>\n<p>\u0646\u062d\u0648\u0647 \u0627\u062f\u063a\u0627\u0645 \u0628\u0647\u0627\u0631 \u062f\u0631 \u06a9\u0627\u0631\u0627\u062a\u0647<\/p>\n<p>\u0646\u0645\u0648\u0646\u0647 \u06a9\u0627\u0645\u0644 \u067e\u0631\u0648\u0698\u0647: https:\/\/github.com\/trey-pero\/karate-spring<\/p>\n<p>\u06a9\u0627\u0631\u0627\u062a\u0647 \u0631\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646 \u0627\u0632 \u0637\u0631\u06cc\u0642 \u06cc\u06a9 \u062a\u0633\u062a \u0633\u0627\u062f\u0647 JUnit \u0627\u062c\u0631\u0627 \u06a9\u0631\u062f.  \u0628\u0631\u0627\u06cc \u0634\u0631\u0648\u0639 \u0633\u06cc\u0645 \u06a9\u0634\u06cc Spring in\u060c \u062a\u0633\u062a JUnit \u0631\u0627 \u0628\u0647 \u0639\u0646\u0648\u0627\u0646 @SpringBootTest \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f.<\/p>\n<p>@RequiredArgsConstructor<br \/>\n@SpringBootTest(classes = Main.class)<br \/>\npublic class KarateTest {<br \/>\n    private final ApplicationContext applicationContext;<\/p>\n<p>    @Test<br \/>\n    void test() {<br \/>\n        ApplicationContextHolder.setApplicationContext(this.applicationContext);<\/p>\n<p>        \/\/ Since this one JUnit test runs all Karate tests,<br \/>\n        \/\/ fail the test if any underlying Karate tests fail<br \/>\n        assertEquals(0, Runner.path(&#8220;classpath:org\/tpero&#8221;)<br \/>\n                .parallel(Optional.ofNullable(System.getProperty(&#8220;karate.threads&#8221;))<br \/>\n                        .map(Integer::parseInt)<br \/>\n                        .orElse(5)<br \/>\n                ).getFailCount());<br \/>\n    }<br \/>\n}<\/p>\n<p>    \u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/p>\n<p>    \u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/p>\n<p>\u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0645\u062a\u0646 Spring (\u06a9\u0647 \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u062a\u0645\u0627\u0645 \u062f\u0627\u0646\u0647 \u0647\u0627 \u0648 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0631\u0627 \u0641\u0631\u0627\u0647\u0645 \u0645\u06cc \u06a9\u0646\u062f)\u060c \u0628\u0627\u06cc\u062f \u062f\u0631 \u062c\u0627\u06cc\u06cc \u0630\u062e\u06cc\u0631\u0647 \u0634\u0648\u062f \u06a9\u0647 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0628\u062a\u0648\u0627\u0646\u062f \u0628\u0647 \u0635\u0648\u0631\u062a \u0627\u06cc\u0633\u062a\u0627 \u0628\u0647 \u0622\u0646 \u062f\u0633\u062a\u0631\u0633\u06cc \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.<\/p>\n<p>\/**<br \/>\n * Provides Karate static access to the Spring application context.<br \/>\n *\/<br \/>\n@UtilityClass<br \/>\npublic class ApplicationContextHolder {<br \/>\n    @Setter<br \/>\n    @Getter<br \/>\n    private ApplicationContext applicationContext;<br \/>\n}<\/p>\n<p>    \u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/p>\n<p>    \u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/p>\n<p>\u0627\u0632 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647\u060c \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0646\u0645\u0648\u0646\u0647 \u0632\u06cc\u0631 \u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 \u0646\u06af\u0647\u062f\u0627\u0631\u0646\u062f\u0647 \u062b\u0627\u0628\u062a \u062f\u0633\u062a\u0631\u0633\u06cc \u062f\u0627\u0634\u062a \u062a\u0627 \u0632\u0645\u06cc\u0646\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0631\u0627 \u0628\u0647 \u0646\u0642\u0634\u0647 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u062c\u0647\u0627\u0646\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u0645\u062a\u0635\u0644 \u06a9\u0646\u062f:<\/p>\n<p>\/**<br \/>\n * Define common feature file configuration here.<br \/>\n * @returns Common configuration as a JSON object.<br \/>\n *\/<br \/>\nfunction getConfig() {<br \/>\n    \/\/ Global values<br \/>\n    const appContext = Java.type(&#8220;org.tpero.ApplicationContextHolder&#8221;)<br \/>\n        .getApplicationContext()<br \/>\n    const environment = appContext.getEnvironment()<\/p>\n<p>    return {<br \/>\n        appContext: appContext,<br \/>\n        environment: environment,<\/p>\n<p>        baseUrl: `http:\/\/localhost:${environment.getProperty(&#8216;app.server.port&#8217;, &#8216;8080&#8217;)}`<br \/>\n    }<br \/>\n}<\/p>\n<p>    \u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/p>\n<p>    \u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/p>\n<p>\u0628\u0627 \u06a9\u062f \u0631\u0627\u0647\u200c\u0627\u0646\u062f\u0627\u0632\u06cc \u0628\u0627\u0644\u0627\u060c \u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 beans \u0648 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0627\u0632 \u0641\u0627\u06cc\u0644\u200c\u0647\u0627\u06cc \u0648\u06cc\u0698\u06af\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u062f\u0633\u062a\u0631\u0633\u06cc \u067e\u06cc\u062f\u0627 \u06a9\u0631\u062f\u060c \u06a9\u0647 \u0628\u0627 \u0627\u06cc\u0646 \u0646\u0645\u0648\u0646\u0647 \u0646\u0634\u0627\u0646 \u062f\u0627\u062f\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a \u06a9\u0647 \u06cc\u06a9 API \u0648\u0631\u0648\u062f \u0633\u0627\u062f\u0647 \u0631\u0627 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0645\u06cc\u200c\u06a9\u0646\u062f \u06a9\u0647 \u06cc\u06a9 \u062a\u0648\u06a9\u0646 JWT \u0631\u0627 \u0628\u0631\u0645\u06cc\u200c\u06af\u0631\u062f\u0627\u0646\u062f.<\/p>\n<p>Feature: Login<br \/>\n  Background:<br \/>\n    * url baseUrl<br \/>\n    * path &#8216;\/login&#8217;<br \/>\n    # Load the JWT service bean from Spring DI<br \/>\n    * def jwtService = appContext.getBean(&#8216;jwtService&#8217;)<\/p>\n<p>  Scenario: Login with valid credentials<br \/>\n    Given request { username: &#8216;user&#8217;, password: &#8216;password&#8217; }<br \/>\n    When method post<br \/>\n    Then status 200<br \/>\n    * print response<\/p>\n<p>    # Use the JWT service bean to decode the JWT from the response<br \/>\n    * def decodedJwt = jwtService.decode(response)<br \/>\n    * print decodedJwt<br \/>\n    * def decodedBody = decodedJwt.getBody()<br \/>\n    * print decodedBody<\/p>\n<p>    And match decodedBody[&#8216;sub&#8217;] == &#8216;user&#8217;<br \/>\n    * def issuedAt = Number(decodedBody[&#8216;iat&#8217;])<br \/>\n    # Ensure the issuedAt is in the past<br \/>\n    And assert issuedAt <\/p>\n<p>    \u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/p>\n<p>    \u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/p>\n<p>\u0627\u06cc\u0646 \u0646\u0645\u0648\u0646\u0647 \u0646\u0634\u0627\u0646 \u0645\u06cc\u200c\u062f\u0647\u062f \u06a9\u0647 \u0686\u0642\u062f\u0631 \u0622\u0633\u0627\u0646 \u0627\u0633\u062a \u06a9\u0647 \u0642\u062f\u0631\u062a Spring Boot \u0631\u0627 \u062f\u0631 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0628\u0631\u0627\u06cc \u0633\u0627\u062e\u062a\u0646 \u0645\u062c\u0645\u0648\u0639\u0647\u200c\u0647\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u062a\u0648\u0627\u0646\u0645\u0646\u062f\u062a\u0631 \u0627\u062f\u063a\u0627\u0645 \u06a9\u0646\u06cc\u062f. <\/p>\n<div data-article-id=\"1931218\" id=\"article-body\">\n<p>\u0686\u0646\u062f \u0633\u0627\u0644\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0645\u0646 \u0627\u0632 \u062e\u06cc\u0627\u0631 \u0628\u0631\u0627\u06cc \u062a\u0633\u062a \u0647\u0627\u06cc \u0633\u0637\u062d \u0628\u0627\u0644\u0627\u062a\u0631 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u06a9\u0646\u0645 \u0648 \u0627\u062e\u06cc\u0631\u0627\u064b \u06a9\u0627\u0631\u0627\u062a\u0647 \u0631\u0627 \u0634\u0631\u0648\u0639 \u06a9\u0631\u062f\u0647 \u0627\u0645.  \u062f\u0631 \u062d\u0627\u0644\u06cc \u06a9\u0647 \u062e\u06cc\u0627\u0631 \u06cc\u06a9 \u0627\u0628\u0632\u0627\u0631 \u0639\u0627\u0644\u06cc \u0627\u0633\u062a\u060c \u0645\u0646 \u0641\u06a9\u0631 \u0645\u06cc\u200c\u06a9\u0646\u0645 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0648\u0627\u0642\u0639\u0627\u064b \u062f\u0631 \u06a9\u0627\u0647\u0634 \u062d\u062c\u0645 \u062f\u06cc\u06af \u06a9\u0647 \u0647\u0645\u0631\u0627\u0647 \u0628\u0627 \u062a\u0639\u0627\u0631\u06cc\u0641 \u0645\u0631\u062d\u0644\u0647\u200c\u0627\u06cc \u0627\u0633\u062a \u0645\u06cc\u200c\u062f\u0631\u062e\u0634\u062f \u0648 \u0646\u0648\u0634\u062a\u0646 \u0633\u0631\u06cc\u0639 \u062a\u0633\u062a\u200c\u0647\u0627\u06cc \u0645\u0639\u0646\u06cc\u200c\u062f\u0627\u0631 \u0631\u0627 \u0622\u0633\u0627\u0646 \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0645\u062e\u0635\u0648\u0635\u0627\u064b \u0648\u0642\u062a\u06cc \u0635\u062d\u0628\u062a \u0627\u0632 \u062a\u0633\u062a API \u0645\u06cc\u200c\u0634\u0648\u062f.<\/p>\n<p>\u0628\u0631\u0627\u06cc \u0628\u0631\u0646\u0627\u0645\u0647 \u0647\u0627\u06cc \u0633\u0627\u062f\u0647\u060c \u0646\u0648\u0634\u062a\u0646 \u0641\u0627\u06cc\u0644 \u0647\u0627\u06cc \u0648\u06cc\u0698\u06af\u06cc \u062e\u0648\u062f \u062f\u0631 \u062c\u0627\u0648\u0627 \u0627\u0633\u06a9\u0631\u06cc\u067e\u062a \u0633\u0627\u062f\u0647 \u06a9\u0627\u0641\u06cc \u0627\u0633\u062a.  \u0628\u0627 \u0631\u0634\u062f \u0628\u0631\u0646\u0627\u0645\u0647 \u0648 \u062a\u0633\u062a \u0647\u0627\u06cc \u0634\u0645\u0627\u060c \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u062c\u062f\u062f \u0627\u0632 \u0628\u0631\u062e\u06cc \u06a9\u062f\u0647\u0627\u06cc \u062c\u0627\u0648\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646\u062f \u0627\u0631\u0632\u0634\u0645\u0646\u062f \u0628\u0627\u0634\u062f.  API \u0647\u0627\u06cc Spring Boot \u0645\u06cc \u062a\u0648\u0627\u0646\u0646\u062f \u0627\u0632 \u062a\u0633\u062a \u06a9\u0627\u0631\u0627\u062a\u0647 \u0633\u0648\u062f \u0632\u06cc\u0627\u062f\u06cc \u0628\u0628\u0631\u0646\u062f\u060c \u0627\u0645\u0627 \u062f\u0631 \u0645\u0648\u0631\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0642\u062f\u0631\u062a Spring Boot \u0628\u0647 \u0637\u0648\u0631 \u0645\u0633\u062a\u0642\u06cc\u0645 \u062f\u0631 \u062a\u0633\u062a \u0647\u0627\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u0686\u0637\u0648\u0631\u061f<\/p>\n<p><strong>\u0686\u0646\u062f \u0646\u0645\u0648\u0646\u0647 \u0627\u0632 \u0645\u0648\u0627\u0631\u062f \u0627\u0633\u062a\u0641\u0627\u062f\u0647<\/strong><\/p>\n<ul>\n<li>\u062f\u0631 \u062d\u0627\u0644\u06cc \u06a9\u0647 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0627\u0632 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0627\u0632 \u0637\u0631\u06cc\u0642 \u0641\u0627\u06cc\u0644\u200c\u0647\u0627\u06cc karate-config.js \u067e\u0634\u062a\u06cc\u0628\u0627\u0646\u06cc \u0645\u06cc\u200c\u06a9\u0646\u062f\u060c \u0628\u0631\u062e\u06cc \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0628\u0647 \u062c\u0627\u06cc \u0622\u0646 \u0627\u0632 \u0637\u0631\u06cc\u0642 Spring YAML\/properties \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u06a9\u0646\u0646\u062f.  \u0627\u06cc\u0646 \u0645\u06cc \u062a\u0648\u0627\u0646\u062f \u0628\u0631\u0627\u06cc \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0645\u062c\u062f\u062f \u0645\u0648\u0627\u0631\u062f \u062e\u0627\u0631\u062c \u0627\u0632 \u06a9\u062f \u0628\u0627\u0632\u0633\u0627\u0632\u06cc \u0646\u06cc\u0632 \u0645\u0641\u06cc\u062f \u0628\u0627\u0634\u062f.<\/li>\n<li>\u0628\u0631\u0627\u06cc \u0647\u0645\u06af\u0627\u0645\u200c\u0633\u0627\u0632\u06cc \u0628\u0631\u062e\u06cc \u0648\u06cc\u0698\u06af\u06cc\u200c\u0647\u0627\u06cc \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc Spring Boot \u0628\u06cc\u0646 \u0628\u0631\u0646\u0627\u0645\u0647\u200c\u0647\u0627 \u0648 \u0622\u0632\u0645\u0627\u06cc\u0634\u200c\u0647\u0627.<\/li>\n<li>\u0628\u0631\u0627\u06cc \u062a\u0623\u06cc\u06cc\u062f \u0648\u0636\u0639\u06cc\u062a \u067e\u0627\u06cc\u06af\u0627\u0647 \u062f\u0627\u062f\u0647 \u0628\u06cc\u0646 \u062a\u0645\u0627\u0633 \u0647\u0627\u06cc API.  \u0645\u062e\u0632\u0646 JPA\/\u062d\u0628\u0648\u0628\u0627\u062a \u0645\u0648\u062c\u0648\u062f\u06cc\u062a \u0631\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646 \u062f\u0631 \u0622\u0632\u0645\u0648\u0646 \u0647\u0627\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u06a9\u0631\u062f.<\/li>\n<li>\u0628\u0631\u062e\u06cc \u0627\u0632 \u0644\u0648\u0628\u06cc\u0627\u0647\u0627\u06cc \u0628\u0647\u0627\u0631 \u0645\u0645\u06a9\u0646 \u0627\u0633\u062a \u0628\u0647 \u0633\u0627\u062f\u06af\u06cc \u0628\u0631\u0627\u06cc \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u062f\u0631 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0647\u0627 \u0645\u0641\u06cc\u062f \u0628\u0627\u0634\u0646\u062f.<\/li>\n<\/ul>\n<p><strong>\u0646\u062d\u0648\u0647 \u0627\u062f\u063a\u0627\u0645 \u0628\u0647\u0627\u0631 \u062f\u0631 \u06a9\u0627\u0631\u0627\u062a\u0647<\/strong><\/p>\n<p>\u0646\u0645\u0648\u0646\u0647 \u06a9\u0627\u0645\u0644 \u067e\u0631\u0648\u0698\u0647: https:\/\/github.com\/trey-pero\/karate-spring<\/p>\n<p>\u06a9\u0627\u0631\u0627\u062a\u0647 \u0631\u0627 \u0645\u06cc \u062a\u0648\u0627\u0646 \u0627\u0632 \u0637\u0631\u06cc\u0642 \u06cc\u06a9 \u062a\u0633\u062a \u0633\u0627\u062f\u0647 JUnit \u0627\u062c\u0631\u0627 \u06a9\u0631\u062f.  \u0628\u0631\u0627\u06cc \u0634\u0631\u0648\u0639 \u0633\u06cc\u0645 \u06a9\u0634\u06cc Spring in\u060c \u062a\u0633\u062a JUnit \u0631\u0627 \u0628\u0647 \u0639\u0646\u0648\u0627\u0646 @SpringBootTest \u062a\u0646\u0638\u06cc\u0645 \u06a9\u0646\u06cc\u062f.<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>@RequiredArgsConstructor\n@SpringBootTest(classes = Main.class)\npublic class KarateTest {\n    private final ApplicationContext applicationContext;\n\n    @Test\n    void test() {\n        ApplicationContextHolder.setApplicationContext(this.applicationContext);\n\n        \/\/ Since this one JUnit test runs all Karate tests,\n        \/\/ fail the test if any underlying Karate tests fail\n        assertEquals(0, Runner.path(\"classpath:org\/tpero\")\n                .parallel(Optional.ofNullable(System.getProperty(\"karate.threads\"))\n                        .map(Integer::parseInt)\n                        .orElse(5)\n                ).getFailCount());\n    }\n}\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0628\u0631\u0627\u06cc \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u0645\u062a\u0646 Spring (\u06a9\u0647 \u062f\u0633\u062a\u0631\u0633\u06cc \u0628\u0647 \u062a\u0645\u0627\u0645 \u062f\u0627\u0646\u0647 \u0647\u0627 \u0648 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0631\u0627 \u0641\u0631\u0627\u0647\u0645 \u0645\u06cc \u06a9\u0646\u062f)\u060c \u0628\u0627\u06cc\u062f \u062f\u0631 \u062c\u0627\u06cc\u06cc \u0630\u062e\u06cc\u0631\u0647 \u0634\u0648\u062f \u06a9\u0647 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0628\u062a\u0648\u0627\u0646\u062f \u0628\u0647 \u0635\u0648\u0631\u062a \u0627\u06cc\u0633\u062a\u0627 \u0628\u0647 \u0622\u0646 \u062f\u0633\u062a\u0631\u0633\u06cc \u062f\u0627\u0634\u062a\u0647 \u0628\u0627\u0634\u062f.<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\/**\n * Provides Karate static access to the Spring application context.\n *\/\n@UtilityClass\npublic class ApplicationContextHolder {\n    @Setter\n    @Getter\n    private ApplicationContext applicationContext;\n}\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0627\u0632 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647\u060c \u0628\u0627 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0627\u0632 \u0646\u0645\u0648\u0646\u0647 \u0632\u06cc\u0631 \u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 \u0646\u06af\u0647\u062f\u0627\u0631\u0646\u062f\u0647 \u062b\u0627\u0628\u062a \u062f\u0633\u062a\u0631\u0633\u06cc \u062f\u0627\u0634\u062a \u062a\u0627 \u0632\u0645\u06cc\u0646\u0647 \u0628\u0631\u0646\u0627\u0645\u0647 \u0631\u0627 \u0628\u0647 \u0646\u0642\u0634\u0647 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u062c\u0647\u0627\u0646\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u0645\u062a\u0635\u0644 \u06a9\u0646\u062f:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>\/**\n * Define common feature file configuration here.\n * @returns Common configuration as a JSON object.\n *\/\nfunction getConfig() {\n    \/\/ Global values\n    const appContext = Java.type(\"org.tpero.ApplicationContextHolder\")\n        .getApplicationContext()\n    const environment = appContext.getEnvironment()\n\n    return {\n        appContext: appContext,\n        environment: environment,\n\n        baseUrl: `http:\/\/localhost:${environment.getProperty('app.server.port', '8080')}`\n    }\n}\n<\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0628\u0627 \u06a9\u062f \u0631\u0627\u0647\u200c\u0627\u0646\u062f\u0627\u0632\u06cc \u0628\u0627\u0644\u0627\u060c \u0645\u06cc\u200c\u062a\u0648\u0627\u0646 \u0628\u0647 beans \u0648 \u067e\u06cc\u06a9\u0631\u0628\u0646\u062f\u06cc \u0627\u0632 \u0641\u0627\u06cc\u0644\u200c\u0647\u0627\u06cc \u0648\u06cc\u0698\u06af\u06cc \u06a9\u0627\u0631\u0627\u062a\u0647 \u062f\u0633\u062a\u0631\u0633\u06cc \u067e\u06cc\u062f\u0627 \u06a9\u0631\u062f\u060c \u06a9\u0647 \u0628\u0627 \u0627\u06cc\u0646 \u0646\u0645\u0648\u0646\u0647 \u0646\u0634\u0627\u0646 \u062f\u0627\u062f\u0647 \u0634\u062f\u0647 \u0627\u0633\u062a \u06a9\u0647 \u06cc\u06a9 API \u0648\u0631\u0648\u062f \u0633\u0627\u062f\u0647 \u0631\u0627 \u0622\u0632\u0645\u0627\u06cc\u0634 \u0645\u06cc\u200c\u06a9\u0646\u062f \u06a9\u0647 \u06cc\u06a9 \u062a\u0648\u06a9\u0646 JWT \u0631\u0627 \u0628\u0631\u0645\u06cc\u200c\u06af\u0631\u062f\u0627\u0646\u062f.<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Feature: Login\n  Background:\n    * url baseUrl\n    * path '\/login'\n    # Load the JWT service bean from Spring DI\n    * def jwtService = appContext.getBean('jwtService')\n\n  Scenario: Login with valid credentials\n    Given request { username: 'user', password: 'password' }\n    When method post\n    Then status 200\n    * print response\n\n    # Use the JWT service bean to decode the JWT from the response\n    * def decodedJwt = jwtService.decode(response)\n    * print decodedJwt\n    * def decodedBody = decodedJwt.getBody()\n    * print decodedBody\n\n    And match decodedBody['sub'] == 'user'\n    * def issuedAt = Number(decodedBody['iat'])\n    # Ensure the issuedAt is in the past\n    And assert issuedAt <\/code><\/pre>\n<div class=\"highlight__panel js-actions-panel\">\n<div class=\"highlight__panel-action js-fullscreen-code-action\">\n    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-on\"><title>\u0648\u0627\u0631\u062f \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z\"\/>\n<\/svg><\/p>\n<p>    <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"20px\" height=\"20px\" viewbox=\"0 0 24 24\" class=\"highlight-action crayons-icon highlight-action--fullscreen-off\"><title>\u0627\u0632 \u062d\u0627\u0644\u062a \u062a\u0645\u0627\u0645 \u0635\u0641\u062d\u0647 \u062e\u0627\u0631\u062c \u0634\u0648\u06cc\u062f<\/title>\n    <path d=\"M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z\"\/>\n<\/svg><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p>\u0627\u06cc\u0646 \u0646\u0645\u0648\u0646\u0647 \u0646\u0634\u0627\u0646 \u0645\u06cc\u200c\u062f\u0647\u062f \u06a9\u0647 \u0686\u0642\u062f\u0631 \u0622\u0633\u0627\u0646 \u0627\u0633\u062a \u06a9\u0647 \u0642\u062f\u0631\u062a Spring Boot \u0631\u0627 \u062f\u0631 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0628\u0631\u0627\u06cc \u0633\u0627\u062e\u062a\u0646 \u0645\u062c\u0645\u0648\u0639\u0647\u200c\u0647\u0627\u06cc \u0622\u0632\u0645\u0627\u06cc\u0634\u06cc \u062a\u0648\u0627\u0646\u0645\u0646\u062f\u062a\u0631 \u0627\u062f\u063a\u0627\u0645 \u06a9\u0646\u06cc\u062f. <\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Summarize this content to 400 words in Persian Lang \u0686\u0646\u062f \u0633\u0627\u0644\u06cc \u0627\u0633\u062a \u06a9\u0647 \u0645\u0646 \u0627\u0632 \u062e\u06cc\u0627\u0631 \u0628\u0631\u0627\u06cc \u062a\u0633\u062a \u0647\u0627\u06cc \u0633\u0637\u062d \u0628\u0627\u0644\u0627\u062a\u0631 \u0627\u0633\u062a\u0641\u0627\u062f\u0647 \u0645\u06cc \u06a9\u0646\u0645 \u0648 \u0627\u062e\u06cc\u0631\u0627\u064b \u06a9\u0627\u0631\u0627\u062a\u0647 \u0631\u0627 \u0634\u0631\u0648\u0639 \u06a9\u0631\u062f\u0647 \u0627\u0645. \u062f\u0631 \u062d\u0627\u0644\u06cc \u06a9\u0647 \u062e\u06cc\u0627\u0631 \u06cc\u06a9 \u0627\u0628\u0632\u0627\u0631 \u0639\u0627\u0644\u06cc \u0627\u0633\u062a\u060c \u0645\u0646 \u0641\u06a9\u0631 \u0645\u06cc\u200c\u06a9\u0646\u0645 \u06a9\u0627\u0631\u0627\u062a\u0647 \u0648\u0627\u0642\u0639\u0627\u064b \u062f\u0631 \u06a9\u0627\u0647\u0634 \u062d\u062c\u0645 \u062f\u06cc\u06af \u06a9\u0647 \u0647\u0645\u0631\u0627\u0647 \u0628\u0627 \u062a\u0639\u0627\u0631\u06cc\u0641 \u0645\u0631\u062d\u0644\u0647\u200c\u0627\u06cc \u0627\u0633\u062a \u0645\u06cc\u200c\u062f\u0631\u062e\u0634\u062f &hellip;<\/p>\n","protected":false},"author":2,"featured_media":70318,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"","fifu_image_alt":"","footnotes":""},"categories":[339],"tags":[],"class_list":["post-70317","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dev"],"_links":{"self":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/70317","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/comments?post=70317"}],"version-history":[{"count":0,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/posts\/70317\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media\/70318"}],"wp:attachment":[{"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/media?parent=70317"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/categories?post=70317"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nabfollower.com\/blog\/wp-json\/wp\/v2\/tags?post=70317"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}