ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

Java

[Spring] Mockito๋ž€?

๊ฐœ๋ฐœ๊ฐœ๊ตด๐Ÿธ 2023. 5. 21. 20:47

๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ž€?

๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋Š” ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์„ ๊ธฐ์ค€์œผ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์ง„ํ–‰๋˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์˜ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ๋…๋ฆฝ์ ์œผ๋กœ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์€ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์„œ ๊ฐ ๋‹จ์œ„๊ฐ€ ์ •ํ™•ํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฌธ์ œ ๋ฐœ์ƒ ์‹œ ์ •ํ™•ํ•˜๊ฒŒ ์–ด๋Š ๋ถ€๋ถ„์ด ์ž˜๋ชป๋˜์—ˆ๋Š”์ง€ ์บ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์ง€๋งŒ, ๋‹ค๋ฅธ ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š” ๊ฒฝ์šฐ์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด Service ๊ณ„์ธต์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋ณดํ†ต ๋‹ค๋ฅธ ๊ฐ์ฒด๋“ค๊ณผ ์˜์กด ๊ด€๊ณ„๋ฅผ ๋งบ๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ, Bean Container์— ์ฃผ์ž…๋œ ์‹ค์ œ ๊ฐ์ฒด๋“ค์„ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๊ณ , Mockito ํ”„๋ ˆ์ž„์›Œํฌ ๋“ฑ์„ ํ™œ์šฉํ•ด Mock ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์“ฐ๋Š” ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.


Mockito๋ž€?

Mockito๋Š” *JUnit Test์—์„œ *Mock์„ ์œ„ํ•œ Java ์˜คํ”ˆ์†Œ์Šค ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

 

Spring์€ ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋“ค ๊ฐ„์˜ ์˜์กด์„ฑ์ด ์ƒ๊ธฐ๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ํŠน์„ฑ์€ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๊ฐœ๋ฐœ์ž๊ฐ€ ๋™์ž‘์„ ์ง์ ‘ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์งœ ๊ฐ์ฒด์ธ Mock์„ ์ƒ์„ฑํ•˜์—ฌ ์ฃผ์ž…์‹œ์ผœ์ฃผ๋Š” Mockito ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

์ฆ‰, Mockito๋Š” Mock ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ณ , ๊ด€๋ฆฌํ•˜๊ณ , ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

 

*Mock: ์ง„์งœ ๊ฐ์ฒด์™€ ๋น„์Šทํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ, ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์ง์ ‘ ํ–‰๋™์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด

*JUnit: ์ž๋ฐ” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ


Mockito ์‹œ์ž‘ํ•˜๊ธฐ

Dependency ์ถ”๊ฐ€

์Šคํ”„๋ง ๋ถ€ํŠธ 2.2 ์ด์ƒ ๋ฒ„์ „์˜ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์‹œ spring-boot-start-test์—์„œ ์ž๋™์œผ๋กœ Mockito๋ฅผ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.

dependencies {
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

 

์ง์ ‘ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด์„  mockito-core์™€ mockito-junit-jupiter๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • mockito-core: mockito๊ฐ€ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ธฐ๋ณธ์ ์ธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • mockito-junit-jupiter: junit ํ…Œ์ŠคํŠธ์—์„œ mockito๋ฅผ ์—ฐ๋™ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” junit ํ™•์žฅ ๊ตฌํ˜„์ฒด
// build.gradle
dependencies {
    testImplementation 'org.mockito:mockito-core:3.11.2'
    testImplementation 'org.mockito:mockito-junit-jupiter:3.11.2'   
}

//maven
 <dependency>       
 	<groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.1.0</version>
    <scope>test</scope>
</dependency>

<dependency>
	<groupId>org.mockito</groupId>
	<artifactId>mockito-junit-jupiter</artifactId>
	<version>3.1.0</version>
	<scope>test</scope>
</dependency>

 

JUnit๊ณผ ๊ฒฐํ•ฉ

Mockito๋„ ํ…Œ์ŠคํŒ… ํ”„๋ ˆ์ž„์›Œํฌ์ด๊ธฐ ๋•Œ๋ฌธ์— JUnit๊ณผ ๊ฒฐํ•ฉ๋˜๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ™์ด๋Š” ๋ณ„๋„์˜ ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  • JUnit4: @RunWith(MockitoJUnitRunner.class)
  • JUnit5: @ExtendWith(MockitoExtension.class)

SpringBoot 2.2.0๋ถ€ํ„ฐ ๊ณต์‹์ ์œผ๋กœ JUnit5๋ฅผ ์ง€์›ํ•จ์— ๋”ฐ๋ผ @ExtendWith(MockitoExtension.class)๋ฅผ ์‚ฌ์šฉํ•ด ๊ฒฐํ•ฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

@ExtendWith(MockitoExtension.class)
class Test {
	// ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
}

Mockito ์‚ฌ์šฉํ•˜๊ธฐ

์šฐ์„  ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์— ์•ž์„œ Member๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์„ธํŒ…์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

(ํŽธ์˜์„ฑ์„ ์œ„ํ•ด ์ €๋Š” Lombok์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.)

 

Member

package com.example.demotest.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Getter
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "member")
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_no")
    private Long no;

    @Setter
    @Column(name = "name", nullable = false)
    private String name;

}
  • Member Entity๋ฅผ ์ƒ์„ฑ

 

Repository

import com.example.demotest.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {
}
  • Member๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ Repository๋ฅผ ์ƒ์„ฑ

 

Service

import com.example.demotest.domain.Member;
import com.example.demotest.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {

    private final MemberRepository memberRepository;

    public List<Member> findAllMember() {
        return memberRepository.findAll();
    }

}
  • Member List๋ฅผ ์กฐํšŒํ•˜๋Š” ์„œ๋น„์Šค๋ฅผ ์ƒ์„ฑ

 

๋‹ค์Œ์œผ๋กœ MemberService๋ฅผ ํ†ตํ•ด Member List๋ฅผ ์กฐํšŒํ•˜๋Š” Service Test ์˜ˆ์‹œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import com.example.demotest.domain.Member;
import com.example.demotest.repository.MemberRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.assertj.core.api.Assertions;

import java.util.ArrayList;
import java.util.List;

@ExtendWith(MockitoExtension.class)
class MemberServiceTest {

    @InjectMocks
    private MemberService memberService;

    @Mock
    private MemberRepository memberRepository;

    @Test
    @DisplayName("ํšŒ์› ์กฐํšŒ ๊ฒฐ๊ณผ Member ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋ฐ˜ํ™˜๋˜์–ด์•ผ ํ•œ๋‹ค.")
    void findAllMember() {
        // given
        List<Member> memberList = new ArrayList<>();
        memberList.add(new Member(
                1L,
                "name1"));
        memberList.add(new Member(
                2L,
                "name2"));


        // when
        Mockito.when(memberRepository.findAll()).thenReturn(memberList);
        List<Member> result = memberService.findAllMember();

        // then
        Assertions.assertThat(result).hasSize(2);
        Assertions.assertThat(result.get(0).getName()).isEqualTo("name1");
        Assertions.assertThat(result.get(1).getName()).isEqualTo("name2");
    }
}
  • @Mock
    • Mock๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
  • @InjectMocks
    • @Mock์ด ๋ถ™์€ Mock๊ฐ์ฒด๋ฅผ @InjectMocks์ด ๋ถ™์€ ๊ฐ์ฒด์— ์ฃผ์ž…
    • Service๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด์„œ MemberRespository๋ฅผ ์ฃผ์ž…๋ฐ›์•„์•ผ ํ•จ
  • Mock ๊ฐ์ฒด Stubbing
    • when() -> memberRepository๋ฅผ ํ†ตํ•ด ํšŒ์› ๋ฆฌ์ŠคํŠธ๋ฅผ ์กฐํšŒ ํ–ˆ์„๋•Œ
    • thenReturn() -> memberList๊ฐ€ return ๋˜์–ด์•ผ ํ•จ
  • Test ์ง„ํ–‰
    • Repository์—์„œ ์กฐํšŒํ•œ ๊ฒฐ๊ณผ์™€ Service๋ฅผ ํ†ตํ•ด ์กฐํšŒํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ต
    • ์ƒ์„ฑํ•œ MemberList์˜ ํฌ๊ธฐ๋Š” 2
    • ์ฒซ๋ฒˆ์งธ ๊ฐ’์˜ ์ด๋ฆ„์€ name1
    • ๋‘๋ฒˆ์งธ ๊ฐ’์˜ ์ด๋ฆ„์€ name2

 

ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ ๊ฒฐ๊ณผ passed๊ฐ€ ์ž˜ ๋‚˜์˜ต๋‹ˆ๋‹ค!

 

์ž‘์„ฑ ์ฝ”๋“œ๋Š” ์•„๋ž˜ ๋งํฌ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/Jisue/Spring-Test/tree/main/demo-test

 

GitHub - Jisue/Spring-Test: TDD Study

TDD Study. Contribute to Jisue/Spring-Test development by creating an account on GitHub.

github.com


[์ฐธ๊ณ ]

https://mangkyu.tistory.com/145

 

[Spring] JUnit๊ณผ Mockito ๊ธฐ๋ฐ˜์˜ Spring ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ๋ฒ• (3/3)

์ด๋ฒˆ์—๋Š” Spring ๊ธฐ๋ฐ˜์˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 1. Mockito ์†Œ๊ฐœ ๋ฐ ์‚ฌ์šฉ๋ฒ• [ Mockito๋ž€? ] Mockito๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋™์ž‘์„ ์ง์ ‘ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€์งœ ๊ฐ

mangkyu.tistory.com

https://scshim.tistory.com/439

 

Mockito๋ž€? Mockito ์‚ฌ์šฉํ•˜๊ธฐ

Mockito๋ž€? · Mock ๊ฐ์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ณ , ๊ด€๋ฆฌํ•˜๊ณ , ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ - Mock: ์ง„์งœ ๊ฐ์ฒด์™€ ๋น„์Šทํ•˜๊ฒŒ ๋™์ž‘ํ•˜์ง€๋งŒ, ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์ง์ ‘ ํ–‰๋™์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด - ๊ณตํ™ˆ https://site.m

scshim.tistory.com

https://www.nextree.io/mockito/

 

Mockito๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

Mockito ๋ž€? Mockito๋ž€ Java ์˜คํ”ˆ์†Œ์Šค ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. Mockito๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ๋ชจ๋ฐฉํ•œ ๊ฐ€์งœ ๊ฐ์ฒด, Mock ๊ฐ์ฒด ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” ์ด Mock ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ๋ณด๋‹ค ๊ฐ„๋‹จํ•˜

www.nextree.io

https://lemontia.tistory.com/951

 

[junit5] Mock์„ ์ด์šฉํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (@InjectMocks ๊ณผ @Mock ์ฐจ์ด)

Mockito๋ฅผ ์ด์šฉํ•˜๋ฉด ์ข€๋” ์ž‘์€ ๋‹จ์œ„๊นŒ์ง€ ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ฌด์—‡๋ณด๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ์ปจํŠธ๋กคํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์—์„œ DB์—ฐ๊ฒฐ์—†์ด ์ž„์˜๋กœ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ ์šฉํ•˜๋‹ค. ์ด๋ฒˆ์—๋Š” ๊ทธ ํ…Œ์ŠคํŠธ์— ๊ด€ํ•œ ๋‚ด์šฉ

lemontia.tistory.com

https://velog.io/@hellonayeon/spring-boot-service-layer-unit-testcode

 

[Spring Boot] Service ๊ณ„์ธต์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

 

velog.io

 

https://velog.io/@sussa3007/Spring-JUnit-Mockito-%EA%B8%B0%EB%B0%98-Spring-%EB%8B%A8%EC%9C%84-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%BD%94%EB%93%9C-%EC%9E%91%EC%84%B1

 

[Spring] JUnit & Mockito ๊ธฐ๋ฐ˜ Spring ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

๋‹จ์œ„ํ…Œ์ŠคํŠธ๋Š” ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์„ ๊ธฐ์ค€์œผ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์ง„ํ–‰๋˜๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„์˜ ํ…Œ์ŠคํŠธ๋‹ค.ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ์ด๋ž€ ๊ฐ ๊ณ„์ธต์—์„œ์˜ ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ ๋˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™

velog.io

 

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

[Spring] Feign Client๋ž€?  (2) 2023.11.03