Spring Boot ๋‹จ์œ„ ํ…Œ์ŠคํŠธ: @Mock ๊ณผ @InjectionMocks์˜ ์›๋ฆฌ์™€ ํ™œ์šฉ

2025. 2. 14. 18:02ยทAlgoMate

๐Ÿง 1. Mockito๋ž€? (์™œ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?)

Mockito ๋ž€ Java์—์„œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ Mocking ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ํŠน์ • ๊ฐ์ฒด๋ฅผ ์‹ค์ œ ๊ฐ์ฒด์ฒ˜๋Ÿผ ํ‰๋‚ด ๋‚ด๋Š” ๊ฐ€์งœ(Mock) ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด์„œ, ํ…Œ์ŠคํŠธ ์ค‘ ํŠน์ • ๋™์ž‘์„ ์ •์˜ํ•˜๊ณ  ์˜ˆ์ƒ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ… ์™œ Mocking์ด ํ•„์š”ํ• ๊นŒ?

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์˜์กด์„ฑ ์ œ๊ฑฐ: Repository๋‚˜ ์™ธ๋ถ€ API๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ๋А๋ ค์ง€๊ณ  ํ™˜๊ฒฝ์— ์˜์กด์ ์ด ๋œ๋‹ค.
  • ์ •ํ™•ํ•œ ํ…Œ์ŠคํŠธ ๋ณด์žฅ: ํŠน์ • ๋ฉ”์„œ๋“œ๊ฐ€ ์ •ํ™•ํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ํ…Œ์ŠคํŠธ ์†๋„ ํ–ฅ์ƒ: ์‹ค์ œ DB ์—ฐ๊ฒฐ ์—†์ด ์›ํ•˜๋Š” ๊ฐ’์„ ๋ณ€ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ•˜๋ฉด ๋น ๋ฅธ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

๐Ÿ”ฅ Mock์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ vs ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

Mock์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ Mock์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—†์ด ๋…๋ฆฝ์ ์ธ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‹ค์ œ ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„์„ ๊ฒ€์ฆํ•ด์•ผ ํ•  ๋•Œ
์™ธ๋ถ€ API ํ˜ธ์ถœ ์—†์ด ๋น ๋ฅด๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์„ ๋•Œ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋‚˜ E2E ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ
ํŠน์ • ๋ฉ”์„œ๋“œ์˜ ๋™์ž‘์„ ๋‹จ๋…์œผ๋กœ ๊ฒ€์ฆํ•˜๊ณ  ์‹ถ์„ ๋•Œ ํŠธ๋žœ์žญ์…˜์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋˜๋Š”์ง€ ํ™•์ธํ•  ๋•Œ

 

์ฆ‰, ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์—์„œ๋Š” Mock์„ ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ ,

ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ(E2E ํ…Œ์ŠคํŠธ)์—์„œ๋Š” ์‹ค์ œ DB์™€ API๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ์ ˆํ•˜๋‹ค.

๐Ÿ— 2. @Mock๊ณผ @InjectMocks์˜ ์›๋ฆฌ

โœ… @Mock

  • Mockito์—์„œ ํŠน์ • ๊ฐ์ฒด๋ฅผ Mockingํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
  • ์›๋ž˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹ , ํ•ด๋‹น ๊ฐ์ฒด์˜ ๊ฐ€์งœ(Stub) ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • when().thenReturn()์œผ๋กœ ์›ํ•˜๋Š” ๋™์ž‘์„ ๋ฏธ๋ฆฌ ์ •์˜ ๊ฐ€๋Šฅํ•˜๋‹ค.

โœ… @InjectMocks

  • @Mock์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์ฃผ์ž…(Inject)ํ•˜์—ฌ,
    ์šฐ๋ฆฌ๊ฐ€ ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” @InjectMocks ๋Œ€์ƒ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.

๐Ÿ“Œ ์˜ˆ์ œ ์ฝ”๋“œ

@Mock
private SolutionRepository solutionRepository;  // Mock ๊ฐ์ฒด ์ƒ์„ฑ

@InjectMocks
private SolutionService solutionService;  // solutionRepository๊ฐ€ ์ž๋™ ์ฃผ์ž…๋จ

 

์œ„ ์ฝ”๋“œ์—์„œ solutionRepository๋Š” Mock ๊ฐ์ฒด์ด์ง€๋งŒ, solutionService์—์„œ๋Š” ์›๋ž˜ ๊ฐ์ฒด์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

๐Ÿ” 3. Mockito๊ฐ€ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€?

Mockito๋Š” ํ”„๋ก์‹œ(Proxy) ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ์›๋ž˜ ๊ฐ์ฒด์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด.

  1. @Mock์„ ์‚ฌ์šฉํ•˜๋ฉด, ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ์•„๋‹ˆ๋ผ Proxy ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
  2. when().thenReturn()์„ ์‚ฌ์šฉํ•˜๋ฉด ํŠน์ • ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ๋ฏธ๋ฆฌ ์ •์˜๋œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •๋œ๋‹ค.
  3. @InjectMocks๊ฐ€ ์‚ฌ์šฉ๋œ ํด๋ž˜์Šค์—๋Š” @Mock์œผ๋กœ ๋งŒ๋“  ๊ฐ€์งœ ๊ฐ์ฒด๊ฐ€ ์ฃผ์ž…๋œ๋‹ค.
  4. ์‹ค์ œ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ, Mock ๊ฐ์ฒด๋Š” ์›๋ž˜ ๋กœ์ง์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  Mockito๊ฐ€ ๋ฏธ๋ฆฌ ์„ค์ •ํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

๐Ÿ›  4. ์ฝ”๋“œ ์˜ˆ์ œ: Repository๋ฅผ Mockingํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ

@Test
void givenMoreThan100Solutions_whenCheckingThreshold_thenReturnsTrue() {
    // given
    String problemId = "1000";
    String language = "Java";

    // Mock ๊ฐ์ฒด์˜ ๋™์ž‘์„ ์„ค์ • (์‹ค์ œ DB์— ์ ‘๊ทผํ•˜์ง€ ์•Š์Œ)
    when(solutionRepository.countByProblemIdAndLanguage(problemId, language))
            .thenReturn(150L); // 150๊ฐœ๋กœ ์„ค์ •

    // when
    boolean result = solutionService.hasAtLeast100Solutions(problemId, language);

    // then
    assertTrue(result);
}

โœ… ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์‹คํ–‰ ํ๋ฆ„

  1. solutionRepository.countByProblemIdAndLanguage(problemId, language) ํ˜ธ์ถœ๋œ๋‹ค.
  2. ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์กฐํšŒํ•˜์ง€ ์•Š๊ณ , when().thenReturn(150L)์ด ์„ค์ •ํ•œ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  3. solutionService.hasAtLeast100Solutions()์—์„œ count >= 100์„ ์ฒดํฌํ•˜์—ฌ true ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  4. assertTrue(result);์—์„œ ๊ฒ€์ฆ ์„ฑ๊ณต! โœ…

๐Ÿ•ต๏ธ‍โ™‚๏ธ 5. Mockito ๋‚ด๋ถ€ ๋™์ž‘์„ ๋””๋ฒ„๊น…ํ•ด๋ณด๊ธฐ

ํ…Œ์ŠคํŠธ ์ค‘์— Mockito์˜ Mock ๊ฐ์ฒด๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด,
System.out.println()์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋””๋ฒ„๊ฑฐ๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
void debugMockitoBehavior() {
    // given
    String problemId = "2000";
    String language = "Python";

    when(solutionRepository.countByProblemIdAndLanguage(problemId, language))
            .thenReturn(80L); // 80๊ฐœ๋กœ ์„ค์ •

    System.out.println("Mock ๊ฐ์ฒด ํ˜ธ์ถœ ์ „");  // ๋””๋ฒ„๊น…์šฉ ๋กœ๊ทธ

    // when
    boolean result = solutionService.hasAtLeast100Solutions(problemId, language);

    System.out.println("Mock ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’: " 
        + solutionRepository.countByProblemIdAndLanguage(problemId, language));

    // then
    assertFalse(result);
}

 

โœ… ์ถœ๋ ฅ ๊ฒฐ๊ณผ

Mock ๊ฐ์ฒด ํ˜ธ์ถœ ์ „
Mock ๊ฐ์ฒด๊ฐ€ ๋ฐ˜ํ™˜ํ•œ ๊ฐ’: 80
  • solutionRepository.countByProblemIdAndLanguage()๊ฐ€ ์‹ค์ œ DB๋ฅผ ์กฐํšŒํ•œ ๊ฒŒ ์•„๋‹ˆ๋ผ,
    Mockito๊ฐ€ ์„ค์ •ํ•œ ๊ฐ’(80)์„ ๋ฐ˜ํ™˜ํ•œ ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

โœจ ๊ฒฐ๋ก 

โœ… @Mock์€ ๊ฐ€์งœ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ํ…Œ์ŠคํŠธ ์‹œ ์˜์กด์„ฑ์„ ์ œ๊ฑฐํ•˜๊ณ  ๋…๋ฆฝ์ ์ธ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ.
โœ… @InjectMocks๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, Mock ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ ์ฃผ์ž…ํ•˜์—ฌ ์›๋ž˜ ์„œ๋น„์Šค ํด๋ž˜์Šค์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
โœ… when().thenReturn()์„ ํ™œ์šฉํ•˜๋ฉด ํŠน์ • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ ์›ํ•˜๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Œ.
โœ… Mockito๋Š” ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‹ค์ œ ๊ฐ์ฒด์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋Š” ์›๋ฆฌ๋กœ ์ž‘๋™ํ•จ.

'AlgoMate' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Celery + Redis vs Celery + RabbitMQ: ์–ด๋–ค ์„ ํƒ์ด ๋” ๋‚˜์„๊นŒ?  (0) 2025.02.17
๐Ÿš€ ๋™์ ์œผ๋กœ ํŒŒ์ผ์„ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•  (2) 2025.02.16
AlgoMate#3 - docker ๋กœ ๋„์šด DB ์— ์ ‘๊ทผํ•˜๊ธฐ(PostgreSQL)  (2) 2025.02.01
AlgoMate#2 - Jplag๋ฅผ ํ†ตํ•œ ์œ ์‚ฌ๋„ ๊ฒ€์‚ฌ  (2) 2025.02.01
Algomate#1 - ๋‚ด ์ •๋‹ต๊ณผ ์œ ์‚ฌํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ •๋‹ต์„ ์ถ”์ฒœํ•ด์ค€๋‹ค๊ณ ??!  (0) 2025.01.30
'AlgoMate' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • Celery + Redis vs Celery + RabbitMQ: ์–ด๋–ค ์„ ํƒ์ด ๋” ๋‚˜์„๊นŒ?
  • ๐Ÿš€ ๋™์ ์œผ๋กœ ํŒŒ์ผ์„ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ๋ฒ•
  • AlgoMate#3 - docker ๋กœ ๋„์šด DB ์— ์ ‘๊ทผํ•˜๊ธฐ(PostgreSQL)
  • AlgoMate#2 - Jplag๋ฅผ ํ†ตํ•œ ์œ ์‚ฌ๋„ ๊ฒ€์‚ฌ
SungHoJung
SungHoJung
  • SungHoJung
    HOLOUD
    SungHoJung
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (40)
      • AlgoMate (13)
      • TroubleShooting (0)
      • ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ชจ์Œ์ง‘ (4)
      • Infra (17)
  • ๋งํฌ

    • github
  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    EC2
    ECS
    ํฌ๋กค๋งํ•œ ๋ฐ์ดํ„ฐ
    redis
    Celery
    ๋ฉ”์„ธ์ง€ ๋ธŒ๋กœ์ปค
    ์ปจํ…Œ์ด๋„ˆ ๊ฐ„ ํ†ต์‹ 
    AWS
    host.docker.internal
    bypass recaptcha
    celery+redis
    Kubernetes
    ์Šค์™‘ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •
    recaptcha ์šฐํšŒ
    IAM
    celery+rabbitmq
    ci-cd
    docker-compose
    ๋กœ์ปฌ ์„œ๋ฒ„์™€ ํ†ต์‹ 
    k8s
  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
SungHoJung
Spring Boot ๋‹จ์œ„ ํ…Œ์ŠคํŠธ: @Mock ๊ณผ @InjectionMocks์˜ ์›๋ฆฌ์™€ ํ™œ์šฉ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”