티스토리 뷰

반응형

13. 13. 가짜객체 ~ 14. 14. 가게 추가 - 1 ( 가짜 객체 중요)

mock objectmockito 라는 프레임 워크를 이용해 온전히 테스트에 집중하기 위한 가짜 객체( 따라하는)  를 만들 수 있다.

 

가짜객체를 이용하면, 테스트가 좀더 가벼워지고, 독립적으로 온전히  테스트 할 수 있다.

 

 

 

package com.fastcampus.eatgo.interfaces;

import com.fastcampus.eatgo.application.RestaurantService;
import com.fastcampus.eatgo.domain.*;
import com.fastcampus.eatgo.domain.MenuItem;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.Matchers.containsString;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

//스프링을 이용해서 이 테스트를 진행해라.
// 안쓰는 import 정리 ctrl alt o
@RunWith(SpringRunner.class)
@WebMvcTest(RestaurantController.class) //이 컨트롤러를 검사해라.
public class RestaurantControllerTest {
    @Autowired
    private MockMvc mvc;
//
//    // 컨트롤러에 원하는 객체 주입
//    @SpyBean(RestaurantRepositoryImpl.class)
//    private RestaurantRepository restaurantRepository;

    // 가짜 객체 만들기: 의존성 있는 친구들을 진짜 만드는 것이 아니라 가짜로 만들어준다.
    @MockBean// 서비스 구현에 불문하고 controller 의 테스트만 온번히 가능
    private RestaurantService restaurantService;

    //    @SpyBean(RestaurantService.class)
    //    private RestaurantService restaurantService;g
    //    @SpyBean(MenuItemRepositoryImpl.class)
    //    private MenuItemRepository menuItemRepository;

    @Test
    public void list() throws Exception {


        List<Restaurant> restaurants = new ArrayList<>();
        restaurants.add(new Restaurant(1004L, "Bob zip", "Seoul"));
        restaurants.add(new Restaurant(2020L, "Bob2 zip", "Seoul"));
        given(restaurantService.getRestaurants()).willReturn(restaurants);// 가짜로 데이터 삽입


        mvc.perform(get("/restaurants")).andExpect(status().isOk()).andExpect(content().string(

                containsString("\"name\":" +
                        "\"Bob zip\""))).andExpect(content().string(

                containsString("\"id\":" +
                        "1004")));// 이 데이터에서 문자열 이것이 포함되어있는지 확인

    }

    @Test
    public void detail() throws Exception {


        Restaurant restaurant1 = new Restaurant(1004L, "Bob zip", "Seoul");
        Restaurant restaurant2 = new Restaurant(2020L, "Bob2 zip", "Seoul");
        restaurant1.addMenuItem(new MenuItem("Kimchi"));
        given(restaurantService.getRestaurant(1004L)).willReturn(restaurant1);
        given(restaurantService.getRestaurant(2020L)).willReturn(restaurant2); // 가짜 객체가 이걸  보내줄 것이다.  : given 


        mvc.perform(get("/restaurants/1004")).andExpect(status().isOk()).andExpect(content().string(

                containsString("\"name\":" +
                        "\"Bob zip\""))).andExpect(content().string(

                containsString("\"id\":" +
                        "1004"))).andExpect(content().string(

                containsString("Kimchi")));// 이 데이터에서 문자열 이것이 포함되어있는지 확인
        mvc.perform(get("/restaurants/2020")).andExpect(status().isOk()).andExpect(content().string(

                containsString("\"name\":" +
                        "\"Bob2 zip\""))).andExpect(content().string(

                containsString("\"id\":" +
                        "2020")));// 이 데이터에서 문자열 이것이 포함되어있는지 확인

    }
}

 

 

 

package com.fastcampus.eatgo.application;

import com.fastcampus.eatgo.domain.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

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

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;
import static org.mockito.BDDMockito.given;

public class RestaurantServiceTest {
    private RestaurantService restaurantService;
    @Mock //가짜 객체 reposit 말고 직접 온전한 서비스 테스트 
    private RestaurantRepository restaurantRepository;
    @Mock //가짜 객체
    private MenuItemRepository menuItemRepository;

    // 스프링이 해줄수 없는 작업들을 미리 한다, 예) 서비스와 레포지토리 연결
    @Before //모든 테스트 시작전에 반드시 이것을 해본다.
    public void setUp() {
        MockitoAnnotations.initMocks(this);//가짜객체 초기화들
        //        restaurantRepository = new RestaurantRepositoryImpl();
        //        menuItemRepository = new MenuItemRepositoryImpl();
        mockRestaurantRespository();
        mockMenuItemRespository();
        restaurantService = new RestaurantService(restaurantRepository, menuItemRepository);

    }

    private void mockMenuItemRespository() {

        List<MenuItem> menuItems = new ArrayList<>();
        menuItems.add(new MenuItem("Kimchi"));
        given(menuItemRepository.findAllByRestaurantId(1004L)).willReturn(menuItems);


    }

    private void mockRestaurantRespository() {
        List<Restaurant> restaurants = new ArrayList<>();
        Restaurant restaurant1 = new Restaurant(1004L, "Bob zip", "Seoul");
        Restaurant restaurant2 = new Restaurant(2020L, "Bob2 zip", "Seoul");

        restaurants.add(restaurant1);
        restaurants.add(restaurant2);
        given(restaurantRepository.findById(1004L)).willReturn(restaurant1);
        given(restaurantRepository.findAll()).willReturn(restaurants);
    }


    @Test
    public void getRestaurant() {
        Restaurant restaurant = restaurantService.getRestaurant(1004L);
        assertThat(restaurant.getId(), is(1004L));
        MenuItem menuItem = restaurant.getMenuItems().get(0);
        assertThat(menuItem.getName(), is("Kimchi"));

    }

    @Test
    public void getRestaurants() {
        List<Restaurant> restaurants = restaurantService.getRestaurants();
        assertThat(restaurants.get(0).getId(), is(1004L));

    }

}

 

 

 

 

httpie 에 대해서 배움. 터미널에서 api 테스트가 가능하다.

post 요청의 ok 는 201 이다. 

status.isCreated()

http GET localhost:8080
http GET localhost:8080/restaurants/1004

ackage kr.co.fastcampus.eatgo.interfaces;

import kr.co.fastcampus.eatgo.application.RestaurantService;
import kr.co.fastcampus.eatgo.domain.Restaurant;
import kr.co.fastcampus.eatgo.domain.RestaurantNotFoundException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

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

import static org.hamcrest.core.StringContains.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest(RestaurantController.class)
public class RestaurantControllerTests {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private RestaurantService restaurantService;

    @Test
    public void list() throws Exception {
        List<Restaurant> restaurants = new ArrayList<>();
        restaurants.add(Restaurant.builder()
                .id(1004L)
                .categoryId(1L)
                .name("JOKER House")
                .address("Seoul")
                .build());

        given(restaurantService.getRestaurants()).willReturn(restaurants);

        mvc.perform(get("/restaurants"))
                .andExpect(status().isOk())
                .andExpect(content().string(
                        containsString("\"id\":1004")
                ))
                .andExpect(content().string(
                        containsString("\"name\":\"JOKER House\"")
                ));
    }

    @Test
    public void detailWithExisted() throws Exception {
        Restaurant restaurant = Restaurant.builder()
                .id(1004L)
                .categoryId(1L)
                .name("JOKER House")
                .address("Seoul")
                .build();

        given(restaurantService.getRestaurant(1004L)).willReturn(restaurant);

        mvc.perform(get("/restaurants/1004"))
                .andExpect(status().isOk())
                .andExpect(content().string(
                        containsString("\"id\":1004")
                ))
                .andExpect(content().string(
                        containsString("\"name\":\"JOKER House\"")
                ));
    }

    @Test
    public void detailWithNotExisted() throws Exception {
        given(restaurantService.getRestaurant(404L))
                .willThrow(new RestaurantNotFoundException(404L));

        mvc.perform(get("/restaurants/404"))
                .andExpect(status().isNotFound())
                .andExpect(content().string("{}"));
    }

    @Test
    public void createWithValidData() throws Exception {
        given(restaurantService.addRestaurant(any())).will(invocation -> {
            Restaurant restaurant = invocation.getArgument(0);
            return Restaurant.builder()
                    .id(1234L)
                    .categoryId(1L)
                    .name(restaurant.getName())
                    .address(restaurant.getAddress())
                    .build();
        });

        mvc.perform(post("/restaurants")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"categoryId\":1,\"name\":\"Beryong\"," +
                        "\"address\":\"Busan\"}"))
                .andExpect(status().isCreated())
                .andExpect(header().string("location", "/restaurants/1234"))
                .andExpect(content().string("{}"));

        verify(restaurantService).addRestaurant(any());
    }

    @Test
    public void createWithInvalidData() throws Exception {
        mvc.perform(post("/restaurants")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"categoryId\":1,\"name\":\"\",\"address\":\"\"}"))
                .andExpect(status().isBadRequest());
    }

    @Test
    public void updateWithValidData() throws Exception {
        mvc.perform(patch("/restaurants/1004")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"categoryId\":1,\"name\":\"JOKER Bar\"," +
                        "\"address\":\"Busan\"}"))
                .andExpect(status().isOk());

        verify(restaurantService)
                .updateRestaurant(1004L, 1L, "JOKER Bar", "Busan");
    }

    @Test
    public void updateWithInvalidData() throws Exception {
        mvc.perform(patch("/restaurants/1004")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"categoryId\":1,\"name\":\"\",\"address\":\"\"}"))
                .andExpect(status().isBadRequest());
    }

    @Test
    public void updateWithoutName() throws Exception {
        mvc.perform(patch("/restaurants/1004")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"name\":\"\",\"address\":\"Busan\"}"))
                .andExpect(status().isBadRequest());
    }

}

 

 

 

 

자바 인강이 듣고 싶다면 =>https://bit.ly/3ilMbIO

반응형
댓글