单测-让我们保持短小而专注于单一行为

assertThat

 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");
  }
}

 

controller

@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());
    }

数据库事务

单测-让我们保持短小而专注于单一行为_第1张图片

建表语句不是必须文件

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");
    }
}

 

kafka

topic

public static final String TOPIC_USER_PROMOTION_MESSAGE = "user_promotion_message";

consumer

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

你可能感兴趣的:(单测-让我们保持短小而专注于单一行为)