JUnit
Junit 5 for String Boot
Gradle νμΌμ μΆκ°
κΈ°μ‘΄ λ€λ₯Έ μμ‘΄μ± λΌμ΄λΈλ¬λ¦¬μ λ³λλ‘ junit-jupiter:5.5.2
μΆκ°
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompile 'org.junit.jupiter:junit-jupiter:5.5.2';
}
Spring MockMvc μΈν
SpringTestUpport.java
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = ShortenApplication.class)
public abstract class SpringTestSupport { }
SpringMockMvcTestSupport.java
@AutoConfigureMockMvc
μ΄λ
Έν
μ΄μ
μ μ΄μ©νμ¬ μλμΌλ‘ ꡬμ±νλ€.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.test.web.servlet.MockMvc;
@AutoConfigureMockMvc
public class SpringMockMvcTestSupport extends SpringTestSupport{
@Autowired
public MockMvc mockMvc;
}
μ°Έκ³ μλ£
https://effectivesquid.tistory.com/entry/Spring-Boot-starter-test-μ-Junit5λ₯Ό-μ΄μ©ν-ν μ€νΈ
κΈ°λ³Έ μ¬μ©λ²
MVC ν μ€νΈνκΈ°
μλμ κ°μ΄ SpringMockMvcTestSupport
μ μμλ°μ μ¬μ©
mockMvc
κ°μ²΄μ perform
λ©μλλ₯Ό μ΄μ©νμ¬ νμΈνλ€.
class ShortenWebControllerTest extends SpringMockMvcTestSupport {
/**
* GetμΌλ‘ νΈμΆνλ©΄ λ€μκ³Ό κ°μ΄ λμ
* <pre> - HTTP μ½λλ 200</pre>
* <pre> - λ°νλ λ·°λ index</pre>
* @see ShortenWebController#getPage()
* @throws Exception ResultMatcher
*/
@Test
@DisplayName("μΈλ±μ€ νμ΄μ§ μμ²")
void getPage_001() throws Exception {
mockMvc.perform(
get("/")
).andExpect(
status().isOk()
).andExpect(
view().name("index")
);
}
}
@ParameterizedTest
μ΄λ
Έν
μ΄μ
μ μ΄μ©νμ¬ μ
λ ₯κ°μ λ³ννμ¬ ν
μ€νΈ κ°λ₯νλ€.
/**
* μ κ·μμ μ΄μ©νμ¬ μ ν¨ν URL κ²μ¦ν¨
* @param candidate κ²μ¦ν URL νλͺ©
*/
@ParameterizedTest
@ValueSource(strings = {
"1",
"http:",
"http://",
"httpx://www.google.com",
"httpz://www.google.com",
"http://com",
"www.com",
"google.com",
"www.google.com"
})
@DisplayName("URL μ ν¨μ± κ²μ¦")
@Description("HTTP νλ‘ν μ½ λ° 3μ°¨ λλ©μΈλ νμλ‘ ν¬ν¨νμ¬μΌ ν¨")
void isValid(String candidate) {
assertFalse(URLValidator.isValid(candidate));
}
@MockBean
μ΄λ @SpyBean
κ³Ό κ°μ΄ λλ―Έ κ°μ²΄ νΉμ μ€μ μμ± κ°μ²΄λ₯Ό μ¬μ©νμ¬ ν
μ€νΈ νλ λ°©λ²μ΄ μμΌλ μΆνμ μ 리νκΈ°λ‘ ν¨
μ°Έκ³ μλ£
https://engkimbs.tistory.com/768
https://www.tutorialspoint.com/spring_boot/spring_boot_rest_controller_unit_test.htm
https://jojoldu.tistory.com/226
λμμ± ν μ€νΈ νκΈ°
Fork Join Pool
μ ννλ Fork Join Framework λΌκ³ νλ νλ μμν¬μ΄λ€. ForkJoinPool
μ μ΄ νλ μμν¬μ λνμ μΈ ν΄λμ€μ΄λ©° κΈ°λ³Έμ μΌλ‘ μ€λ λ ν μλΉμ€μ μΌμ’
μ΄λ€.
μ΄ ForkJoinPool
μ κΈ°λ³Έ κ°λ
μ ν° μ
무λ₯Ό μμ μ
무 λ¨μλ‘ μͺΌκ°κ³ , κ°κΈ° λ€λ₯Έ CPU μμ λ³λ ¬λ‘ μ€νν ν κ²°κ³Όλ₯Ό μ·¨ν©νλ λ°©μμ΄λ€.
λ§μΉ λΆν μ 볡 μκ³ λ¦¬μ¦κ³Ό ν‘μ¬νλ©΄ μ¬λ¬ CPU μ½μ΄λ₯Ό νμ©νμ¬ λκΈ°νμ GC λ₯Ό νΌν μ μλ μ¬λ¬ κΈ°λ²μ΄ μ¬μ©λμκΈ° λλ¬Έμ Java λΏλ§μ΄ μλλΌ Scala μμλ λ리 μ¬μ©λκ³ μλ λ³λ ¬ μ²λ¦¬ κΈ°λ²μ΄λ€.
λ€μ μ 리νλ©΄ μλμ κ°λ€.
- ν° μ 무λ₯Ό μμ λ¨μλ‘ μͺΌκ° λ€.
- λΆλͺ¨ μ€λ λλ‘λΆν° μ²λ¦¬ λ‘μ§μ 볡μ¬νμ¬ μλ‘μ΄ μ€λ λλ₯Ό μμ±νμ¬ μ 무λ₯Ό μν (Fork) μν¨λ€.
2
λ₯Ό λ°λ³΅νλ€ νΉμ μ€λ λμμ λμ΄μ Fork κ° μΌμ΄λμ§ μκ³ μ λ¬΄κ° μλ£λλ©΄ κ·Έ κ²°κ³Όλ₯Ό λΆλͺ¨ μ€λ λμμ Join νμ¬ κ°μ μ·¨ν©νλ€.3
μ λ°λ³΅νλ€κ° μ΅μ΄μForkJoinPool
μ μμ±ν μ€λ λλ‘ κ°μ 리ν΄νμ¬ μμ μ μλ£νλ€.
κΈ°λ³Έμ μΌλ‘ ExecutorService
ꡬν체μ΄λ€.
μΌλ° ExecutorService
ꡬνν΄λμ€μλ κΈ°λ³Έμ μΌλ‘ λ€λ₯Έμ μ Work-Stealing μκ³ λ¦¬μ¦μ΄ ꡬνλμ΄ μλ€λ μ μ΄λ€.
μ΄λ μ΅λν CPUμ Task λΆλ°°μ Idle λ₯Ό μ΅μν νκΈ° μν΄ κ³ λ €λμμΌλ©° μ΄λ CPU κ° μμ μ΄ λλ Idle μνκ° λλ©΄ λ€λ₯Έ λκΈ°μ΄μ μμ μ κ°μ Έμ μ²λ¦¬νλ μμ ꡬνμ ν΄μ€λ€.
μ΄μ κ΄λ ¨ν ForkJoinPool μ λν ν΄λμ€λ μμ λ₯Ό μ°Ύμμ νμΈν΄λ³΄μ
νλ‘νΌν° νμΌ μΆκ°
src/test/resources/junit-platform.properties
νμΌ κ²½λ‘μ νλ‘νΌν° νλΌλ©ν° μΆκ° (μμΌλ©΄ μλ‘ μμ±)
junit.jupiter.execution.parallel.enabled = true
junit.jupiter.execution.parallel.mode.default = concurrent
junit.jupiter.execution.parallel.mode.classes.default = concurrent
μ½λ μμ±
public class λμμ±_ν
μ€νΈ {
public boolean getTrue() {
return IntStream.rangeClosed(0, Integer.MAX_VALUE)
.filter(p -> p % 2 == 0)
.noneMatch(p -> p % 2 == 1);
}
}
@Execution(CONCURRENT)
public class λμμ±_ν
μ€νΈTest {
static λμμ±_ν
μ€νΈ t;
@BeforeAll
static void BeforeAll() {
t = new λμμ±_ν
μ€νΈ();
}
@AfterEach
void AfterEach() {
System.out.println("\n");
System.out.println("After Each");
System.out.println("\n");
}
@RepeatedTest(value = 10)
@DisplayName("ν
μ€νΈ μΌμ΄μ€ 1")
void TEST_CASE_1() {
assertTimeout(Duration.ofMillis(5000), () -> assertTrue(t.getTrue()));
}
@RepeatedTest(value = 10)
@DisplayName("ν
μ€νΈ μΌμ΄μ€ 2")
void TEST_CASE_2() {
assertTimeout(Duration.ofMillis(5000), () -> assertTrue(t.getTrue()));
}
}
@BeforeAll
λ‘ ν
μ€νΈ μμμ μ μΈμ€ν΄μ€ κ°μ²΄λ₯Ό μμ±νκ³ κ°κ°μ μ€λ λλ‘ 10λ²μ© λ°λ³΅ μν
μ΄ 5000 Millisecond μ΄λ΄μ μν λͺ©μ μΌλ‘ μμ±ν¨
λ§μ½ λμμ± ν
μ€νΈ μμ΄ κ°μ μ€λ λλ‘ μννλ €λ©΄ μλμ κ°μ΄ @Execution(SAME_THREAD)
μ΄λ
Έν
μ΄μ
μΌλ‘ λ³κ²½
β Log4j Anti-Pattern β