Spring Unit Test

This commit is contained in:
kimyonghwa
2019-04-17 19:24:09 +09:00
parent ad6ab44345
commit e4d5cf3a77
11 changed files with 315 additions and 29 deletions

View File

@@ -33,5 +33,6 @@ dependencies {
runtimeOnly 'com.h2database:h2' runtimeOnly 'com.h2database:h2'
runtimeOnly 'mysql:mysql-connector-java' runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-test'
} }

View File

@@ -32,8 +32,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
.and() .and()
.authorizeRequests() // 다음 리퀘스트에 대한 사용권한 체크 .authorizeRequests() // 다음 리퀘스트에 대한 사용권한 체크
.antMatchers("/*/signin", "/*/signup").permitAll() // 가입 및 인증 주소는 누구나 접근가능 .antMatchers("/*/signin", "/*/signup").permitAll() // 가입 및 인증 주소는 누구나 접근가능
.antMatchers(HttpMethod.GET, "helloworld/**").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능 .antMatchers(HttpMethod.GET, "/helloworld/**").permitAll() // hellowworld로 시작하는 GET요청 리소스는 누구나 접근가능
.antMatchers("/*/users").hasRole("ADMIN")
.anyRequest().hasRole("USER") // 그외 나머지 요청은 모두 인증된 회원만 접근 가능 .anyRequest().hasRole("USER") // 그외 나머지 요청은 모두 인증된 회원만 접근 가능
.and() .and()
.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler()) .exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler())

View File

@@ -12,10 +12,7 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections; import java.util.Collections;
@@ -31,7 +28,7 @@ public class SignController {
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
@ApiOperation(value = "로그인", notes = "이메일 회원 로그인을 한다.") @ApiOperation(value = "로그인", notes = "이메일 회원 로그인을 한다.")
@GetMapping(value = "/signin") @PostMapping(value = "/signin")
public SingleResult<String> signin(@ApiParam(value = "회원ID : 이메일", required = true) @RequestParam String id, public SingleResult<String> signin(@ApiParam(value = "회원ID : 이메일", required = true) @RequestParam String id,
@ApiParam(value = "비밀번호", required = true) @RequestParam String password) { @ApiParam(value = "비밀번호", required = true) @RequestParam String password) {
@@ -43,8 +40,8 @@ public class SignController {
} }
@ApiOperation(value = "가입", notes = "회원가입을 한다.") @ApiOperation(value = "가입", notes = "회원가입을 한다.")
@GetMapping(value = "/signup") @PostMapping(value = "/signup")
public CommonResult signin(@ApiParam(value = "회원ID : 이메일", required = true) @RequestParam String id, public CommonResult signup(@ApiParam(value = "회원ID : 이메일", required = true) @RequestParam String id,
@ApiParam(value = "비밀번호", required = true) @RequestParam String password, @ApiParam(value = "비밀번호", required = true) @RequestParam String password,
@ApiParam(value = "이름", required = true) @RequestParam String name) { @ApiParam(value = "이름", required = true) @RequestParam String name) {

View File

@@ -33,11 +33,11 @@ public class UserController {
} }
@ApiImplicitParams({ @ApiImplicitParams({
@ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = false, dataType = "String", paramType = "header") @ApiImplicitParam(name = "X-AUTH-TOKEN", value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header")
}) })
@ApiOperation(value = "회원 단건 조회", notes = "회원번호(msrl)로 회원을 조회한다") @ApiOperation(value = "회원 단건 조회", notes = "회원번호(msrl)로 회원을 조회한다")
@GetMapping(value = "/user") @GetMapping(value = "/user")
public SingleResult<User> findUserById(@ApiParam(value = "언어", defaultValue = "ko") @RequestParam String lang) { public SingleResult<User> findUser() {
// SecurityContext에서 인증받은 회원의 정보를 얻어온다. // SecurityContext에서 인증받은 회원의 정보를 얻어온다.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String id = authentication.getName(); String id = authentication.getName();

View File

@@ -25,7 +25,7 @@ public class User implements UserDetails {
@Id // pk @Id // pk
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
private long msrl; private long msrl;
@Column(nullable = false, unique = true, length = 30) @Column(nullable = false, unique = true, length = 50)
private String uid; private String uid;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Column(nullable = false, length = 100) @Column(nullable = false, length = 100)

View File

@@ -12,7 +12,7 @@ public class ResponseService {
// enum으로 api 요청 결과에 대한 code, message를 정의합니다. // enum으로 api 요청 결과에 대한 code, message를 정의합니다.
public enum CommonResponse { public enum CommonResponse {
SUCCESS(0, "성공하였습니."); SUCCESS(0, "성공하였습니.");
int code; int code;
String msg; String msg;

View File

@@ -1,16 +0,0 @@
package com.rest.api;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringRestApiApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@@ -0,0 +1,52 @@
package com.rest.api.controller;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
public class HelloControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void helloworldString() throws Exception {
mockMvc.perform(get("/helloworld/string"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType("text/plain;charset=UTF-8"))
.andExpect(content().string("helloworld"));
}
@Test
public void helloworldJson() throws Exception {
mockMvc.perform(get("/helloworld/json"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=utf-8"))
.andExpect(jsonPath("$.message").value("helloworld"));
}
@Test
public void helloworldPage() throws Exception {
mockMvc.perform(get("/helloworld/page"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType("text/html;charset=UTF-8"))
.andExpect(view().name("helloworld"))
.andExpect(content().string("helloworld"));
}
}

View File

@@ -0,0 +1,89 @@
package com.rest.api.controller.v1;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;
import java.time.LocalDateTime;
import java.time.ZoneId;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
public class SignControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void signin() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("id", "happydaddy@naver.com");
params.add("password", "1234");
mockMvc.perform(post("/v1/signin").params(params))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.msg").exists())
.andExpect(jsonPath("$.data").exists());
}
@Test
public void signinFail() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("id", "happydaddy@naver.com");
params.add("password", "12345");
mockMvc.perform(post("/v1/signin").params(params))
.andDo(print())
.andExpect(status().is5xxServerError())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.code").value(-1001))
.andExpect(jsonPath("$.msg").exists());
}
@Test
public void signup() throws Exception {
long epochTime = LocalDateTime.now().atZone(ZoneId.systemDefault()).toEpochSecond();
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("id", "happydaddy_" + epochTime + "@naver.com");
params.add("password", "12345");
params.add("name", "happydaddy_" + epochTime);
mockMvc.perform(post("/v1/signup").params(params))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.msg").exists());
}
@Test
public void signupFail() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("id", "happydaddy@naver.com");
params.add("password", "12345");
params.add("name", "happydaddy");
mockMvc.perform(post("/v1/signup").params(params))
.andDo(print())
.andExpect(status().is5xxServerError())
.andExpect(jsonPath("$.success").value(false))
.andExpect(jsonPath("$.code").value(-9999));
}
}

View File

@@ -0,0 +1,118 @@
package com.rest.api.controller.v1;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
private String token;
@Before
public void setUp() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("id", "happydaddy@naver.com");
params.add("password", "1234");
ResultActions result = mockMvc.perform(post("/v1/signin").params(params))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.msg").exists())
.andExpect(jsonPath("$.data").exists());
String resultString = result.andReturn().getResponse().getContentAsString();
JacksonJsonParser jsonParser = new JacksonJsonParser();
token = jsonParser.parseMap(resultString).get("data").toString();
}
@Test
public void invalidToken() throws Exception {
mockMvc.perform(MockMvcRequestBuilders
.get("/v1/users")
.header("X-AUTH-TOKEN", "XXXXXXXXXX"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(forwardedUrl("/exception/entrypoint"));
}
@Test
@WithMockUser(username = "mockUser", roles = {"ADMIN"}) // 가상의 Mock 유저 대입
public void accessdenied() throws Exception {
mockMvc.perform(MockMvcRequestBuilders
.get("/v1/users"))
//.header("X-AUTH-TOKEN", token))
.andDo(print())
.andExpect(status().isOk())
.andExpect(forwardedUrl("/exception/accessdenied"));
}
@Test
public void findAllUser() throws Exception {
mockMvc.perform(MockMvcRequestBuilders
.get("/v1/users")
.header("X-AUTH-TOKEN", token))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.list").exists());
}
@Test
public void findUser() throws Exception {
mockMvc.perform(MockMvcRequestBuilders
.get("/v1/user")
.header("X-AUTH-TOKEN", token))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data").exists());
}
@Test
public void modify() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("msrl", "1");
params.add("name", "행복전도사");
mockMvc.perform(MockMvcRequestBuilders
.put("/v1/user")
.header("X-AUTH-TOKEN", token)
.params(params))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true));
}
@Test
public void delete() throws Exception {
mockMvc.perform(MockMvcRequestBuilders
.delete("/v1/user/2")
.header("X-AUTH-TOKEN", token))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true));
}
}

View File

@@ -0,0 +1,46 @@
package com.rest.api.repo;
import com.rest.api.entity.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Collections;
import java.util.Optional;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@RunWith(SpringRunner.class)
@DataJpaTest
public class UserJpaRepoTest {
@Autowired
private UserJpaRepo userJpaRepo;
@Autowired
private PasswordEncoder passwordEncoder;
@Test
public void whenFindByUid_thenReturnUser() {
String uid = "angrydaddy@gmail.com";
String name = "angrydaddy";
// given
userJpaRepo.save(User.builder()
.uid(uid)
.password(passwordEncoder.encode("1234"))
.name(name)
.roles(Collections.singletonList("ROLE_USER"))
.build());
// when
Optional<User> user = userJpaRepo.findByUid(uid);
// then
assertTrue(user.isPresent());
assertThat(user.get().getName(), is(name));
}
}