最佳單元測(cè)試實(shí)踐


title: 最佳單元測(cè)試實(shí)踐
date: 2021/09/08 15:11


注:本文使用的是 SpringBootTest2.x + Junit4 + Mockito,本文的前提是你已經(jīng)會(huì)使用這些工具了乐导。

引言:常見(jiàn)單元測(cè)試方法

@RunWith(SpringRunner.class)    
@SpringBootTest(classes = Application.class)    // 1
@Transactional  // 2
@Rollback
public class HelloServiceTest {

    @Autowired
    private HelloService helloService;

    @Test
    public void sayHello() {
        helloService.sayHello("zhangsan");  // 3
    }
}

這樣的寫(xiě)法不符合規(guī)范的地方如下:

  1. 使用 @SpringBootTest注解將主啟動(dòng)類(lèi) Application 的 BeanDefintion 加入到了 Spring 容器中圃泡,從而加載了所有的 Bean,導(dǎo)致大量的時(shí)間耗費(fèi)在于容器啟動(dòng)上祖很。而且笛丙,如果被 @Component 注解的類(lèi)里有多線程方法,那么在你執(zhí)行單元測(cè)試的時(shí)候假颇,由于多線程任務(wù)的影響胚鸯,就可能對(duì)你的數(shù)據(jù)庫(kù)造成了數(shù)據(jù)修改,即使你使用了事務(wù)回滾注解 @Transactional笨鸡。
    • eg. 在我運(yùn)行單元測(cè)試的時(shí)候姜钳,代碼里的其他類(lèi)的多線程中不停接收activeMQ消息,然后更新數(shù)據(jù)庫(kù)中對(duì)應(yīng)的數(shù)據(jù)镜豹。跟單元測(cè)試的執(zhí)行過(guò)程交叉重疊傲须,導(dǎo)致單元測(cè)試失敗。其他組員在操作數(shù)據(jù)庫(kù)的時(shí)候趟脂,也因?yàn)槲覠o(wú)意中帶起的多線程更改了數(shù)據(jù)庫(kù)泰讽,造成了開(kāi)發(fā)上的困難。
  2. 單元測(cè)試應(yīng)與數(shù)據(jù)庫(kù)完全隔離(不應(yīng)受到外界環(huán)境的影響昔期,違反了可重復(fù)的原則)已卸,數(shù)據(jù)庫(kù)相關(guān)操作應(yīng)使用 mock 代替。
  3. 沒(méi)有使用斷言(assert)硼一,無(wú)法實(shí)現(xiàn)自動(dòng)化判斷累澡。

一、單元測(cè)試的原則

1.1 AIR 原則

  • Automatic(自動(dòng)化的):自動(dòng)通過(guò)一系列的斷言給出執(zhí)行結(jié)果般贼,而不需要人為去判斷愧哟,在幾十上百的測(cè)試用例下很難人為的去判斷。
  • Independent(獨(dú)立的):測(cè)試用例之間不能相互依賴影響哼蛆,是獨(dú)立的
  • Repeatable(可重復(fù)的):?jiǎn)卧獪y(cè)試是可以重復(fù)執(zhí)行的蕊梧,不能受到外界環(huán)境的影響,如數(shù)據(jù)庫(kù)腮介、遠(yuǎn)程調(diào)用肥矢、中間件等外部依賴不能影響測(cè)試用例的執(zhí)行。

1.2 BCDE 原則

保證被測(cè)試模塊的交付質(zhì)量叠洗。

  • B:Border甘改,邊界值測(cè)試旅东,包括循環(huán)邊界、特殊取值十艾、特殊時(shí)間點(diǎn)抵代、數(shù)據(jù)順序等。
  • C:Correct疟羹,正確的輸入主守,并得到預(yù)期的結(jié)果。
  • D:Design榄融,與設(shè)計(jì)文檔相結(jié)合参淫,來(lái)編寫(xiě)單元測(cè)試。
  • E:Error愧杯,強(qiáng)制錯(cuò)誤信息輸入(如:非法數(shù)據(jù)涎才、異常流程、業(yè)務(wù)允許外等)力九,并得到預(yù)期的結(jié)果耍铜。

1.3 使用 Mock 對(duì)象

  1. Mock 可以用來(lái)解除外部服務(wù)依賴,從而保證了測(cè)試用例的獨(dú)立性

  2. Mock 可以減少全鏈路測(cè)試數(shù)據(jù)準(zhǔn)備跌前,從而提高了編寫(xiě)測(cè)試用例的速度

    傳統(tǒng)的集成測(cè)試棕兼,需要準(zhǔn)備全鏈路的測(cè)試數(shù)據(jù),可能某些環(huán)節(jié)并不是你所熟悉的抵乓。最后伴挚,耗費(fèi)了大量的時(shí)間和經(jīng)歷,并不一定得到你想要的結(jié)果≡痔浚現(xiàn)在的單元測(cè)試茎芋,只需要模擬上游的輸入數(shù)據(jù),并驗(yàn)證給下游的輸出數(shù)據(jù)蜈出,編寫(xiě)測(cè)試用例并進(jìn)行測(cè)試的速度可以提高很多倍田弥。

  3. Mock可以模擬一些非正常的流程,從而保證了測(cè)試用例的代碼覆蓋率

    根據(jù)單元測(cè)試的BCDE原則铡原,需要進(jìn)行邊界值測(cè)試(Border)和強(qiáng)制錯(cuò)誤信息輸入(Error)偷厦,這樣有助于覆蓋整個(gè)代碼邏輯。在實(shí)際系統(tǒng)中燕刻,很難去構(gòu)造這些邊界值沪哺,也能難去觸發(fā)這些錯(cuò)誤信息。而 Mock 從根本上解決了這個(gè)問(wèn)題:想要什么樣的邊界值酌儒,只需要進(jìn)行Mock;想要什么樣的錯(cuò)誤信息枯途,也只需要進(jìn)行Mock忌怎。

  4. Mock可以不用加載項(xiàng)目環(huán)境配置籍滴,從而保證了測(cè)試用例的執(zhí)行速度
    在進(jìn)行集成測(cè)試時(shí),我們需要加載項(xiàng)目的所有環(huán)境配置榴啸,啟動(dòng)項(xiàng)目依賴的所有服務(wù)接口孽惰。往往執(zhí)行一個(gè)測(cè)試用例,需要幾分鐘乃至幾十分鐘鸥印。采用Mock實(shí)現(xiàn)的測(cè)試用例勋功,不用加載項(xiàng)目環(huán)境配置,也不依賴其它服務(wù)接口库说,執(zhí)行速度往往在幾秒之內(nèi)狂鞋,大大地提高了單元測(cè)試的執(zhí)行速度。

什么是集成測(cè)試潜的?

集成測(cè)試是指在單元測(cè)試的基礎(chǔ)上骚揍,將所有模塊(或單元)按照設(shè)計(jì)要求(如根據(jù)結(jié)構(gòu)圖)組裝成為子系統(tǒng)或系統(tǒng),進(jìn)行集成測(cè)試啰挪。

實(shí)踐表明信不,一些模塊雖然能夠單獨(dú)地工作,但并不能保證連接起來(lái)也能正常的工作亡呵。 一些局部反映不出來(lái)的問(wèn)題抽活,在全局上很可能暴露出來(lái)。

由于集成測(cè)試的單位是一整個(gè)系統(tǒng)锰什,一般有專(zhuān)業(yè)的測(cè)試人員來(lái)進(jìn)行下硕,本文只做簡(jiǎn)單介紹,不繼續(xù)探討歇由。

二卵牍、最佳實(shí)踐

寫(xiě)好單元測(cè)試,以下兩點(diǎn)尤為重要:

  1. 使用 Mock 脫離數(shù)據(jù)庫(kù)
  2. 不使用@SpringBootTest注解加載全部 BeanDefinition沦泌,轉(zhuǎn)而使用@ContextConfiguration注解加載需要的配置類(lèi)

2.1 使用 Mock 代替數(shù)據(jù)庫(kù)

mockito 為 Junit 提供了MockitoJUnitRunner用于解析單元類(lèi)中 mockito 相關(guān)注解糊昙。當(dāng)然使用 SpringRunner 也行,因?yàn)樗麅?nèi)置了 MockitoTestExecutionListener 來(lái)處理 mockito 的注解谢谦。

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.Arrays;
import java.util.List;

@RunWith(MockitoJUnitRunner.class)
// 使用 SpringRunner 也行释牺,因?yàn)樗麅?nèi)置了 MockitoTestExecutionListener 來(lái)處理 mockito 的注解
// @RunWith(SpringRunner.class)
public class MockitoTest {

    /**
     * 如 UserService 是接口,則需 new 出他的實(shí)現(xiàn)類(lèi)回挽,如下:
     *
     * <pre> {@code
     * @InjectMocks
     * private UserService userService = new UserServiceImpl();
     * }</pre>
     * 
     * 否則使用 @InjectMocks 注解無(wú)法注入
     */
    @InjectMocks
    private UserService userService;

    @Mock
    private UserRepository userRepository;

    @Test
    public void test() {

        // 模擬依賴方法
        Mockito.when(userRepository.findAll())
                .thenReturn(Arrays.asList(new User(1, "zs"), new User(2, "ls")));

        // 調(diào)用被測(cè)方法
        List<User> users = userService.listAll();

        // 斷言方法結(jié)果
        Assert.assertEquals(2, users.size());

        // 驗(yàn)證依賴方法
        // 是否只調(diào)用了一次 findAll() 方法
        Mockito.verify(userRepository).findAll();
        // 是否與 userRepository 對(duì)象再無(wú)交互
        Mockito.verifyNoMoreInteractions(userRepository);
    }
}

注:如對(duì)象較大没咙,則可在類(lèi)路徑下存放 json 文件,通過(guò) Json 工具將其序列化成對(duì)象千劈。

Junit5 版祭刚,注意 Test 注解的包名與上面不同

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Arrays;
import java.util.List;

@ExtendWith(MockitoExtension.class)
//@ExtendWith(SpringExtension.class)
public class MockitoTest {

    @InjectMocks
    private UserService userService;

    @Mock
    private UserRepository userRepository;

    @Test
    public void test() {
        
        // 模擬依賴方法
        Mockito.when(userRepository.findAll())
                .thenReturn(Arrays.asList(new User(1, "zs"), new User(2, "ls")));

        // 調(diào)用被測(cè)方法
        List<User> users = userService.listAll();
        
        // 斷言方法結(jié)果
        Assertions.assertEquals(2, users.size());

        // 驗(yàn)證依賴方法
        // 是否只調(diào)用了一次 findAll() 方法
        Mockito.verify(userRepository).findAll();
        // 是否與 userRepository 對(duì)象再無(wú)交互
        Mockito.verifyNoMoreInteractions(userRepository);
    }
}

如果一個(gè)方法的調(diào)用鏈路如下:Controller -> Service -> Repo,那么應(yīng)該將其拆分成兩個(gè)單元來(lái)測(cè)試:

  1. TestController + mockService
  2. TestService -> mockRepo

如果在測(cè)試Controller 的時(shí) mock 了Repo(TestController + @Autowired Service + mockRepo),這樣這就不能叫做單元測(cè)試了涡驮。

單元測(cè)試只保證每個(gè)單元能夠單獨(dú)地工作暗甥,但并不能保證連接起來(lái)也能正常的工作;上面這種多個(gè)跨了多個(gè)單元的應(yīng)該使用集成測(cè)試捉捅。

2.2 只加載需要的 Bean

上面的寫(xiě)法只適用于不使用 Spring 給我們提供的功能情況下撤防,但往往有的時(shí)候我們需要他們給我們提供的功能,就比如通過(guò)@Async注解啟動(dòng)異步任務(wù)棒口。那么這種情況我們要怎樣做單元測(cè)試呢寄月?讓我們回到?jīng)]有 SpringBoot 的時(shí)代,看看 Spring Test 是怎樣進(jìn)行單元測(cè)試的无牵。

Spring Test 為我們提供了@ContextConfiguration注解漾肮,該注解可以加載 Spring 的 xml 配置文件和配置類(lèi),使用方式如下:

被測(cè)試 bean:

@Component
public class AsyncService {

    private static final Logger log = LoggerFactory.getLogger(AsyncService.class);

    @Autowired
    private FeginClient feginClient;

    @Async
    public Future<Integer> startTask(String taskInstanceId) {
        log.info("taskInstanceId:「{}」", taskInstanceId);
        return new AsyncResult<>(feginClient.calc(taskInstanceId));
    }
}

單元測(cè)試:

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.ExecutionException;

@RunWith(SpringRunner.class)
// 只引入需要的 bean
@ContextConfiguration(classes = {
        // 被測(cè) bean
        AsyncService.class,
        // 開(kāi)啟異步注解解析
        SpringTest2.AsyncTestConfig.class,
        // 線程池默認(rèn)的自動(dòng)配置類(lèi)合敦,如果自定義了則替換成自定義的配置類(lèi)
        TaskExecutionAutoConfiguration.class
})
public class SpringTest2 {

    /**
     * 由于需要使用 Spring 提供的異步功能初橘,故需要使用 Spring 提供的 Mock 注解
     */
    @MockBean
    private FeginClient feginClient;

    /**
     * AsyncService 中依賴了 FeginClient,會(huì)將上面 mock 的對(duì)象進(jìn)行 DI
     */
    @Autowired
    private AsyncService asyncService;

    @Test
    public void testCalc() throws ExecutionException, InterruptedException {
        // 模擬依賴方法
        Mockito.when(feginClient.calc(ArgumentMatchers.anyString())).thenReturn(1);

        // 調(diào)用被測(cè)方法
        Integer result = asyncService.startTask("1").get();

        // 斷言方法結(jié)果
        Assert.assertEquals(1, result.intValue());

        // 驗(yàn)證依賴方法
        Mockito.verify(feginClient).calc(ArgumentMatchers.anyString());
        Mockito.verifyNoMoreInteractions(feginClient);
    }

    @EnableAsync
    @Configuration
    public static class AsyncTestConfig {
    }
}

都寫(xiě)的挺好的充岛,按照順序看一下:
https://www.cnblogs.com/myitnews/p/12330297.html
https://fanlychie.github.io/post/spring-boot-testing.html
https://blog.51cto.com/codewalker/4375122

單元測(cè)試:

  • spring test & junit
  • @ContextConfiguration保檐、@RunWith(SpringRunner.class)、@Test

切面測(cè)試(啟動(dòng)一部分組件):

  • spring-boot-test-autoconfig
  • @* Test 系列注解
@DataRedisTest:該注解用于測(cè)試對(duì)Redis操作崔梗,自動(dòng)掃描被@RedisHash描述的類(lèi)夜只,并配置Spring Data Redis的庫(kù)。該注解會(huì)啟動(dòng)一個(gè)內(nèi)存中的Redis服務(wù)器蒜魄,并使用隨機(jī)端口進(jìn)行監(jiān)聽(tīng)扔亥,同時(shí)自動(dòng)配置RedisTemplate和StringRedisTemplate等bean,以便我們可以輕松地執(zhí)行Redis操作谈为。

@DataJpaTest:該注解用于測(cè)試基于JPA的數(shù)據(jù)庫(kù)操作旅挤,同時(shí)提供了TestEntityManager替代JPA的EntityManager。該注解會(huì)用嵌入式的數(shù)據(jù)庫(kù)(例如H2)創(chuàng)建一個(gè)測(cè)試環(huán)境伞鲫,同時(shí)自動(dòng)配置EntityManagerFactory粘茄、DataSource、TransactionManager等bean秕脓,以便我們可以輕松地測(cè)試JPA實(shí)體和Repository層代碼柒瓣。

@DataJdbcTest:該注解用于測(cè)試基于Spring Data JDBC的數(shù)據(jù)庫(kù)操作。該注解會(huì)用嵌入式的數(shù)據(jù)庫(kù)(例如H2)創(chuàng)建一個(gè)測(cè)試環(huán)境吠架,并自動(dòng)配置JdbcTemplate芙贫、NamedParameterJdbcTemplate等bean,以便我們可以輕松地測(cè)試JDBC操作傍药。

@JsonTest:該注解用于測(cè)試JSON的序列化和反序列化磺平。該注解會(huì)自動(dòng)配置Jackson ObjectMapper bean魂仍,并提供了一些輔助方法,方便我們進(jìn)行JSON序列化和反序列化操作褪秀。

@WebMvcTest:該注解用于測(cè)試Spring MVC中的controllers蓄诽。該注解會(huì)自動(dòng)配置MockMvc bean,并提供了一些輔助方法媒吗,方便我們進(jìn)行controller層的測(cè)試操作。

@WebFluxTest:該注解用于測(cè)試Spring WebFlux中的controllers乙埃。該注解會(huì)自動(dòng)配置WebTestClient bean闸英,并提供了一些輔助方法,方便我們進(jìn)行WebFlux相關(guān)的測(cè)試操作介袜。

@RestClientTest:該注解用于測(cè)試對(duì)REST客戶端的操作甫何。該注解會(huì)自動(dòng)配置RestTemplate bean,并提供了一些輔助方法遇伞,方便我們進(jìn)行REST客戶端相關(guān)的測(cè)試操作辙喂。

@DataLdapTest:該注解用于測(cè)試對(duì)LDAP的操作。該注解會(huì)使用嵌入式的LDAP服務(wù)器創(chuàng)建一個(gè)測(cè)試環(huán)境鸠珠,并自動(dòng)配置LdapTemplate bean和EmbeddedLdap bean巍耗,以便我們可以輕松地測(cè)試LDAP操作。

@DataMongoTest:該注解用于測(cè)試對(duì)MongoDB的操作渐排。該注解會(huì)用嵌入式的MongoDB服務(wù)器創(chuàng)建一個(gè)測(cè)試環(huán)境炬太,并自動(dòng)配置MongoTemplate、MongoClient等bean驯耻,以便我們可以輕松地測(cè)試MongoDB操作亲族。

@DataNeo4jTest:該注解用于測(cè)試對(duì)Neo4j的操作。該注解會(huì)使用嵌入式的Neo4j服務(wù)器創(chuàng)建一個(gè)測(cè)試環(huán)境可缚,并自動(dòng)配置Neo4jTemplate霎迫、Neo4jClient等bean,以便我們可以輕松地測(cè)試Neo4j操作帘靡。

功能測(cè)試(啟動(dòng)全部容器):@SpringBootTest

契約測(cè)試:todo

import com.dist.xdata.dgpm.dao.TopicCatalogRepo;
import com.dist.xdata.dgpm.entity.TopicCatalog;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import javax.persistence.EntityManager;
import java.util.List;

/**
 * @author yujx
 * @since 2023/6/13 4:53 PM
 */
@DataJpaTest
@ExtendWith(SpringExtension.class)
public class TestDataJpa {

    @Autowired
    private EntityManager entityManager;

    @Autowired
    private TestEntityManager testEntityManager;

    @Autowired
    private TopicCatalogRepo repo;

    @Test
    public void test() {
        System.out.println("entityManager = " + entityManager);
        System.out.println("testEntityManager = " + testEntityManager);
        
        TopicCatalog save = repo.save(RandomUtil.nextObject(TopicCatalog.class));
        System.out.println("save = " + save);
        List<TopicCatalog> all = repo.findAll();
        System.out.println("all = " + all);
    }
}

https://raw.githubusercontent.com/x54256/pic_home/master/img/202306131738520.png

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末知给,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子测柠,更是在濱河造成了極大的恐慌炼鞠,老刑警劉巖轰胁,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谒主,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡霎肯,警方通過(guò)查閱死者的電腦和手機(jī)擎颖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)观游,“玉大人搂捧,你說(shuō)我怎么就攤上這事《疲” “怎么了允跑?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)搪柑。 經(jīng)常有香客問(wèn)我聋丝,道長(zhǎng),這世上最難降的妖魔是什么工碾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任弱睦,我火速辦了婚禮,結(jié)果婚禮上渊额,老公的妹妹穿的比我還像新娘况木。我一直安慰自己,他們只是感情好旬迹,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布火惊。 她就那樣靜靜地躺著,像睡著了一般舱权。 火紅的嫁衣襯著肌膚如雪矗晃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天宴倍,我揣著相機(jī)與錄音张症,去河邊找鬼。 笑死鸵贬,一個(gè)胖子當(dāng)著我的面吹牛俗他,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阔逼,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼兆衅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了嗜浮?” 一聲冷哼從身側(cè)響起羡亩,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎危融,沒(méi)想到半個(gè)月后畏铆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吉殃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年辞居,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了楷怒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓦灶,死狀恐怖鸠删,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贼陶,我是刑警寧澤刃泡,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站碉怔,受9級(jí)特大地震影響捅僵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜眨层,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望上荡。 院中可真熱鬧趴樱,春花似錦、人聲如沸酪捡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)逛薇。三九已至捺疼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間永罚,已是汗流浹背啤呼。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呢袱,地道東北人官扣。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像羞福,于是被迫代替她去往敵國(guó)和親惕蹄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容