assertThat(a).isEqualTo(1);
//complete the assertion below: a >= 1
assertThat(a).isGreaterThanOrEqualTo(1);
//complete the assertion below: 0 < a < 100
assertThat(a).isStrictlyBetween(0, 100);
//complete the assertion below: a is close to 3.33d
assertThat(a).isCloseTo(3.33d, within(0.1));
assertThat(a).isEqualTo("abc");
assertThat(a).hasSize(3);
assertThat(a).startsWith("abc");
assertThat(a).contains("abc");
assertThat(alphabets).hasSize(3);
assertThat(alphabets).containsExactly("a", "b", "c");
assertThat(alphabets).containsExactlyInAnyOrder("a", "b", "c");
private final UserRepository userRepository = mock(UserRepository.class);
when(userRepository.findOne(0l)).thenReturn(Optional.of(user));
when(userRepository.findOne(user.name())).thenAnswer(answer -> {
user.setId(1l);
return Optional.of(user);
});
assertThat(userId).isOne();
verify(userRepository, times(1)).save(any(User.class));
stubFor(get(urlEqualTo("/users/1")).willReturn(aResponse().withBody("{\"id\":\"1\",\"name\":\"jacky\"}")));
ClassRule、redis
public class RedisContainer extends GenericContainer {
public RedisContainer() {
super("redis:4.0-alpine");
}
@Override
protected void configure() {
super.configure();
withExposedPorts(6379);
}
}
public class Session1_DockerBasedTest {
@ClassRule
public static final RedisContainer REDIS = new RedisContainer();
@Test
public void shouldFetchDataFromCache() throws Exception {
// TODO: make test pass with RedisContainer
RedisCache cache = new RedisCache(REDIS.getContainerIpAddress(),REDIS.getMappedPort(6379));
cache.put("foo", "bar");
String value = cache.get("foo");
assertThat(value).isEqualTo("bar");
}
}
@RunWith(SpringRunner.class)
@WebMvcTest(value = FriendController.class)
public class FriendControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserFriendClient userFriendClient;
@Test
public void getUserFriend() throws Exception {
when(userFriendClient.getUserFriend(1234, 34)).thenReturn(1);
mockMvc.perform(get("/api/activity/friends/relations")
.contentType(APPLICATION_JSON)
.param("userId", "1234")
.param("friendUserId","34"))
.andExpect(status().isOk())
.andExpect(result->result.equals(1));;
}
@Test
public void getUserFriendError() throws Exception {
when(userFriendClient.getUserFriend(1234, 34)).thenReturn(1);
mockMvc.perform(get("/api/activity/friends/relations"))
.andExpect(status().is4xxClientError());
}
}
-------关于异常----------
@Autowired
private MockMvc mockMvc;
// TODO: mock behavior of user service
when(userService.findUser(1)).thenReturn(Optional.of(jack));
// TODO: check response status and response body
mockMvc.perform(get("/users/{id}", 1))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id",is(1)))
.andExpect(jsonPath("$.name",is("jack")));
500异常
@GetMapping("/users/{id}")
@ResponseBody
User getUser(@PathVariable long id) {
Optional user = userService.findUser(id);
return user.orElseThrow(() -> new NoSuchElementException("No such user with id " + id));
}
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
ResponseEntity handleException(Exception ex) {
return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
}
}
@Test
public void shouldReturn500() throws Exception {
// TODO: mock behavior of user service
when(userService.findUser(1)).thenReturn(Optional.empty());
// TODO: check response status and response body
mockMvc.perform(get("/users/{id}", 1))
.andExpect(status().is5xxServerError());
}
建表语句不是必须文件
application.yml
spring:
jpa:
database: h2
show-sql: true
generate-ddl: true
hibernate:
ddl-auto: create
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:test
data: classpath:data.sql
h2:
console:
enabled: true
@RunWith(SpringRunner.class)
@Transactional
@SpringBootTest(classes = MainApp.class)
public class Session2_DatabaseTest {
@Resource
private UserRepo userRepo;
@MockBean
private UserService userService;
@Before
public void setUp() {
DatabasePopulatorUtils.execute(
new ResourceDatabasePopulator(
new ClassPathResource("sql/schema-mysql.sql")),
dataSource);
}
@Test
public void shouldFindUserById() throws Exception {
Optional user = userRepo.findById(1L);
assertThat(user).isPresent();
assertThat(user.get().getName()).isEqualTo("jack");
}
@Test
public void shouldLastDelUserById() throws Exception {
userRepo.deleteById(1L);
Optional user = userRepo.findById(1L);
assertThat(user).isNotPresent();
}
@Test
public void shouldUpdateUserById() throws Exception {
userRepo.save(new UserEntity(1L, "mike"));
Optional user = userRepo.findById(1L);
assertThat(user).isPresent();
assertThat(user.get().getId()).isOne();
assertThat(user.get().getName()).isEqualTo("mike");
}
}
topic
public static final String TOPIC_USER_PROMOTION_MESSAGE = "user_promotion_message";
package com.rcplatform.athena.coin.consumer;
import com.rcplatform.athena.coin.infrastructure.user.UserPromotionMessageMapper;
import com.rcplatform.athena.coin.models.dos.UserPromotionMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
import static com.rcplatform.athena.coin.constant.KafkaTopicConstant.TOPIC_USER_PROMOTION_MESSAGE;
@Component
@Slf4j
class UserPromotionMessageConsumer {
private final UserPromotionMessageMapper promotionMessageMapper;
@Autowired
UserPromotionMessageConsumer(UserPromotionMessageMapper promotionMessageMapper) {
this.promotionMessageMapper = promotionMessageMapper;
}
@KafkaListener(topics = TOPIC_USER_PROMOTION_MESSAGE, containerFactory = "onlyFactory")
void onPromotionMessage(UserPromotionMessage promotionMessage) {
try {
log.warn("user promotion message {}", promotionMessage);
promotionMessageMapper.savePromotionMsg(promotionMessage);
log.debug("Saved user promotion message {}", promotionMessage);
} catch (DuplicateKeyException e) {
log.warn("Promotion message {} for user {} with {} coins already exists",
promotionMessage.getMessageId(),
promotionMessage.getUserId(),
promotionMessage.getCoins(),
e);
}
}
}
package com.rcplatform.athena.coin.consumer;
import com.rcplatform.athena.coin.infrastructure.user.UserPromotionMessageMapper;
import com.rcplatform.athena.coin.models.dos.UserPromotionMessage;
import org.junit.*;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import java.sql.Date;
import java.time.Instant;
import java.util.Random;
import static com.rcplatform.athena.coin.constant.KafkaTopicConstant.TOPIC_USER_PROMOTION_MESSAGE;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.waitAtMost;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = UserKafkaTestApp.class)
@ActiveProfiles("dev")
@EmbeddedKafka(topics = TOPIC_USER_PROMOTION_MESSAGE,
brokerProperties = {
"listeners=PLAINTEXT://localhost:${kafka.broker.port:9092}",
"auto.create.topics.enable=${kafka.broker.topics-enable:true}"})
public class UserPromotionMessageConsumerTest {
private final Random random = new Random(System.currentTimeMillis());
@ClassRule
public static final TemporaryFolder folder = new TemporaryFolder();
@MockBean
private UserPromotionMessageMapper promotionMessageMapper;
@Autowired
private KafkaTemplate kafkaTemplate;
@Autowired
private UserPromotionMessageConsumer promotionMessageConsumer;
private final UserPromotionMessage msg = new UserPromotionMessage();
@Before
public void setUp() {
msg.setMessageId(random.nextLong());
msg.setUserId(random.nextLong());
msg.setCoins(random.nextInt());
msg.setExpiryTime(Date.from(Instant.now()));
System.setProperty("athena.platform.logging.basedir", folder.getRoot().getAbsolutePath());
}
@AfterClass
public static void tearDown() {
System.clearProperty("athena.platform.logging.basedir");
}
@Test
public void shouldPersistMsg() {
kafkaTemplate.send(TOPIC_USER_PROMOTION_MESSAGE, msg);
waitAtMost(10, SECONDS).untilAsserted(() -> verify(promotionMessageMapper).savePromotionMsg(msg));
}
@Test
public void shouldIgnoreDuplicateMsg() {
doNothing().doThrow(DuplicateKeyException.class)
.doThrow(RuntimeException.class)
.when(promotionMessageMapper)
.savePromotionMsg(msg);
promotionMessageConsumer.onPromotionMessage(msg);
promotionMessageConsumer.onPromotionMessage(msg);
try {
promotionMessageConsumer.onPromotionMessage(msg);
fail(RuntimeException.class.getCanonicalName() + " expected");
} catch (RuntimeException e) {
e.printStackTrace();
}
verify(promotionMessageMapper, times(3)).savePromotionMsg(msg);
}
}
@ClassRule
public static final TemporaryFolder folder = new TemporaryFolder();
@BeforeClass
public static void setUp() {
System.setProperty("athena.platform.logging.basedir", folder.getRoot().getAbsolutePath());
}
@AfterClass
public static void tearDown() {
System.clearProperty("athena.platform.logging.basedir");
}
mockito https://skyao.gitbooks.io/learning-java-unit-test/content/mockito/javadoc/mockito10-19.html
partial mock https://blog.csdn.net/neake/article/details/51591268
https://blog.csdn.net/Aeroleo/article/details/49946999?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase
ArgumentCaptor https://www.jianshu.com/p/adee7d28cb59
BDDhttps://en.wikipedia.org/wiki/Behavior-driven_development
WireMockRule
http://wiremock.org/docs/
https://github.com/dadiyang/http-api-invoker/blob/master/src/test/java/com/github/dadiyang/httpinvoker/interfaces/CityServiceTest.java