|
2#
楼主 |
发表于 2018-4-28 15:47:35
|
只看该作者
现在我们已经准备好使用Embed Mongo编写我们的存储库实现的集成测试。
理想情况下,集成测试应该放在单独的源目录中,就像我们放置单元测试(例如src / test / java => src / inte
gration-test / java)。
然而,Maven和Gradle都是灵活的,所以你可以配置POM / build.gradle来处理这个。 然而,为了保持这个讨论
简单和集中,我将把集成测试放在'src / test / java',但我不推荐这个实际应用程序。
让我们开始编写集成测试。 首先,让我们从一个简单的基于JUnit的方法的Test开始。
package com.yohanliyanage.blog.mongoit.repository;
import static org.junit.Assert.fail;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Integration Test for {@link SampleRepositoryMongoImpl}.
*
* @author Yohan Liyanage
*/
public class SampleRepositoryMongoImplIntegrationTest {
private SampleRepositoryMongoImpl repoImpl;
@Before
public void setUp() throws Exception {
repoImpl = new SampleRepositoryMongoImpl();
}
@After
public void tearDown() throws Exception {
}
@Test
public void testSave() {
fail("Not yet implemented");
}
@Test
public void testFindByKey() {
fail("Not yet implemented");
}
}
当这个JUnit测试用例初始化时,我们需要激活EmbedMongo来启动一个嵌入式Mongo服务器。 此外,当测试用例结束时,我们需要清理DB。 以下代码段执行此操作。
package com.yohanliyanage.blog.mongoit.repository;
import static org.junit.Assert.fail;
import java.io.IOException;
import org.junit.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.Mongo;
import com.yohanliyanage.blog.mongoit.model.Sample;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.config.RuntimeConfig;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.extract.UserTempNaming;
/**
* Integration Test for {@link SampleRepositoryMongoImpl}.
*
* @author Yohan Liyanage
*/
public class SampleRepositoryMongoImplIntegrationTest {
private static final String LOCALHOST = "127.0.0.1";
private static final String DB_NAME = "itest";
private static final int MONGO_TEST_PORT = 27028;
private SampleRepositoryMongoImpl repoImpl;
private static MongodProcess mongoProcess;
private static Mongo mongo;
private MongoTemplate template;
@BeforeClass
public static void initializeDB() throws IOException {
RuntimeConfig config = new RuntimeConfig();
config.setExecutableNaming(new UserTempNaming());
MongodStarter starter = MongodStarter.getInstance(config);
MongodExecutable mongoExecutable = starter.prepare(new MongodConfig(Version.V2_2_0, MONGO_TEST_PORT, false));
mongoProcess = mongoExecutable.start();
mongo = new Mongo(LOCALHOST, MONGO_TEST_PORT);
mongo.getDB(DB_NAME);
}
@AfterClass
public static void shutdownDB() throws InterruptedException {
mongo.close();
mongoProcess.stop();
}
@Before
public void setUp() throws Exception {
repoImpl = new SampleRepositoryMongoImpl();
template = new MongoTemplate(mongo, DB_NAME);
repoImpl.setMongoOps(template);
}
@After
public void tearDown() throws Exception {
template.dropCollection(Sample.class);
}
@Test
public void testSave() {
fail("Not yet implemented");
}
@Test
public void testFindByKey() {
fail("Not yet implemented");
}
}
initializeDB()方法用@BeforeClass注释,以在测试用例之前启动它。 此方法触发绑定到给定端口的嵌入式Mon
goDB实例,并暴露设置为使用给定数据库的Mongo对象。 在内部,EmbedMongo在临时目录中创建必要的数
据文件。
当这个方法第一次执行时,EmbedMongo将下载必要的Mongo实现(如上面代码中的Version.V2_2_0所示),
如果它不存在的话。 这是一个不错的设施,特别是当谈到连续集成服务器。 您不必在每个CI服务器中手动设
置Mongo。 这是测试的一个外部依赖。
在用@AfterClass注释的shutdownDB()方法中,我们停止了EmbedMongo进程。 这会在EmbedMongo中触
发必要的清除操作,以删除临时数据文件,将状态恢复到执行测试用例之前的状态。
我们现在更新了setUp()方法来构建Spring MongoTemplate对象,该对象由EmbedMongo公开的Mongo实例
支持,并使用该模板设置我们的RepoImpl。 tearDown()方法被更新以删除“Sample”集合,以确保我们的每
个测试方法都以clean状态开始。
现在只是写实际测试方法的问题。
让我们从保存方法测试开始。
@Test
public void testSave() {
Sample sample = new Sample("TEST", "2");
repoImpl.save(sample);
int samplesInCollection = template.findAll(Sample.class).size();
assertEquals("Only 1 Sample should exist collection, but there are "
+ samplesInCollection, 1, samplesInCollection);
}
我们创建一个Sample对象,将它传递给repoImpl.save(),并断言以确保Sample集合中只有一个Sample。简单,直接的东西。
下面是findByKey方法的测试方法。
@Test
public void testFindByKey() {
// Setup Test Data
List<Sample> samples = Arrays.asList(
new Sample("TEST", "1"), new Sample("TEST", "25"),
new Sample("TEST2", "66"), new Sample("TEST2", "99"));
for (Sample sample : samples) {
template.save(sample);
}
// Execute Test
List<Sample> matches = repoImpl.findByKey("TEST");
// Note: Since our test data (populateDummies) have only 2
// records with key "TEST", this should be 2
assertEquals("Expected only two samples with key TEST, but there are "
+ matches.size(), 2, matches.size());
}
最初,我们通过将一组Sample对象添加到数据存储中来设置数据。 重要的是我们在这里直接使用template.save(),因为repoImpl.save()是一个被测试的方法。 我们不是在这里测试,所以我们在数据设置过程中使用底层的“可信”template.save()。 这是单元/集成测试中的基本概念。 然后我们执行test'findByKey'下的方法,并断言以确保只有两个样本匹配我们的查询。
同样,我们可以继续为每个存储库方法编写更多的测试,包括负测试。 这里是最终的集成测试文件。
package com.yohanliyanage.blog.mongoit.repository;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.junit.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.Mongo;
import com.yohanliyanage.blog.mongoit.model.Sample;
import de.flapdoodle.embed.mongo.MongodExecutable;
import de.flapdoodle.embed.mongo.MongodProcess;
import de.flapdoodle.embed.mongo.MongodStarter;
import de.flapdoodle.embed.mongo.config.MongodConfig;
import de.flapdoodle.embed.mongo.config.RuntimeConfig;
import de.flapdoodle.embed.mongo.distribution.Version;
import de.flapdoodle.embed.process.extract.UserTempNaming;
/**
* Integration Test for {@link SampleRepositoryMongoImpl}.
*
* @author Yohan Liyanage
*/
public class SampleRepositoryMongoImplIntegrationTest {
private static final String LOCALHOST = "127.0.0.1";
private static final String DB_NAME = "itest";
private static final int MONGO_TEST_PORT = 27028;
private SampleRepositoryMongoImpl repoImpl;
private static MongodProcess mongoProcess;
private static Mongo mongo;
private MongoTemplate template;
@BeforeClass
public static void initializeDB() throws IOException {
RuntimeConfig config = new RuntimeConfig();
config.setExecutableNaming(new UserTempNaming());
MongodStarter starter = MongodStarter.getInstance(config);
MongodExecutable mongoExecutable = starter.prepare(new MongodConfig(Version.V2_2_0, MONGO_TEST_PORT, false));
mongoProcess = mongoExecutable.start();
mongo = new Mongo(LOCALHOST, MONGO_TEST_PORT);
mongo.getDB(DB_NAME);
}
@AfterClass
public static void shutdownDB() throws InterruptedException {
mongo.close();
mongoProcess.stop();
}
@Before
public void setUp() throws Exception {
repoImpl = new SampleRepositoryMongoImpl();
template = new MongoTemplate(mongo, DB_NAME);
repoImpl.setMongoOps(template);
}
@After
public void tearDown() throws Exception {
template.dropCollection(Sample.class);
}
@Test
public void testSave() {
Sample sample = new Sample("TEST", "2");
repoImpl.save(sample);
int samplesInCollection = template.findAll(Sample.class).size();
assertEquals("Only 1 Sample should exist in collection, but there are "
+ samplesInCollection, 1, samplesInCollection);
}
@Test
public void testFindByKey() {
// Setup Test Data
List<Sample> samples = Arrays.asList(
new Sample("TEST", "1"), new Sample("TEST", "25"),
new Sample("TEST2", "66"), new Sample("TEST2", "99"));
for (Sample sample : samples) {
template.save(sample);
}
// Execute Test
List<Sample> matches = repoImpl.findByKey("TEST");
// Note: Since our test data (populateDummies) have only 2
// records with key "TEST", this should be 2
assertEquals("Expected only two samples with key TEST, but there are "
+ matches.size(), 2, matches.size());
}
}
另一方面,集成测试的一个关键问题是执行时间。 我们都希望保持我们的测试执行时间尽可能低,最好是几秒钟,
以确保我们可以在CI期间运行所有测试,最小的构建和验证时间。 但是,由于集成测试依赖于底层基础结构,因此
通常集成测试需要时间运行。 但是使用EmbedMongo,情况并非如此。 在我的机器中,上面的测试套件在1.8秒内
运行,每种测试方法最多只有0.166秒。 |
|