이상적으로, 각 테스트 케이스는 서로 분리되어야 한다. 이를 위해 가짜 객체(Mock object)를 생성하는 것도 좋은 방법이다.
그냥 ProductService를 쓰면 되지않냐?
-> Repository를 DI 받을 방법이 없기때문에 쓰임용도만 대체할 MockReposiotry를 만들어서 주입받지않고 생성해줘서 사용한다.
분리 되기 어려운 클래스들
가짜객체 (Mock object) 를 통한 분리 방법
@ExtendWith(MockitoExtension.class)
class ProductServiceTest {
@Mock
ProductRepository productRepository;
@Test
@DisplayName("관심 상품 희망가 - 최저가 이상으로 변경")
void updateProduct_Normal() {
}
class ProductTest {
@Autowired
ProductService productService;
// ...
@Test
@DisplayName("정상 케이스")
void createProduct_Normal() {
// ...
****// 에러 발생! productService 가 null
Product productByService = productService.createProduct(requestDto, userId);
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class ProductIntegrationTest {
@Autowired
ProductService productService;
Long userId = 100L;
Product createdProduct = null;
int updatedMyPrice = -1;
@Test
@Order(1)
@DisplayName("신규 관심상품 등록")
void test1() {
}
testImplementation 'org.springframework.security:spring-security-test'
public class MockSpringSecurityFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
SecurityContextHolder.getContext()
.setAuthentication((Authentication) ((HttpServletRequest) req).getUserPrincipal());
chain.doFilter(req, res);
}
@Override
public void destroy() {
SecurityContextHolder.clearContext();
}
}
@WebMvcTest(
controllers = {UserController.class, ProductController.class},
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = WebSecurityConfig.class
)
}
)
class UserProductMvcTest {
private MockMvc mvc;
private Principal mockPrincipal;
@Autowired
private WebApplicationContext context;
@Autowired
private ObjectMapper objectMapper;
@MockBean
UserService userService;
@MockBean
KakaoUserService kakaoUserService;
@MockBean
ProductService productService;
@BeforeEach
public void setup() {
mvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity(new MockSpringSecurityFilter()))
.build();
}
private void mockUserSetup() {
// Mock 테스트 유져 생성
String username = "제이홉";
String password = "hope!@#";
String email = "hope@sparta.com";
UserRoleEnum role = UserRoleEnum.USER;
User testUser = new User(username, password, email, role);
UserDetailsImpl testUserDetails = new UserDetailsImpl(testUser);
mockPrincipal = new UsernamePasswordAuthenticationToken(testUserDetails, "", testUserDetails.getAuthorities());
}
@Test
@DisplayName("로그인 view")
void test1() throws Exception {
// when - then
mvc.perform(get("/user/login"))
.andExpect(status().isOk())
.andExpect(view().name("login"))
.andDo(print());
}