简体   繁体   English

如何编写数据库单元测试?

[英]How do I write a database unit test?

I'm using MongoDB, Java, JDO and Maven. 我正在使用MongoDB,Java,JDO和Maven。

I ran a simple main application that stores some junk data and retrieves it from mongodb and it looks ok, but I want to start writing proper unit tests. 我运行了一个简单的主应用程序,该应用程序存储了一些垃圾数据并从mongodb中检索了数据,看起来还不错,但是我想开始编写适当的单元测试。 Mocking out the actual database interactions doesn't seem very helpful to me so technically I want to write functional tests that check the full interaction with a database. 模拟实际的数据库交互对我似乎没有太大帮助,因此从技术上讲,我想编写功能测试来检查与数据库的完整交互。

My unit test is set up like this: 我的单元测试设置如下:

static final Logger LOG = LoggerFactory.getLogger(DaoTest.class);
static final int PORT = 100001;
static Process mongod;
static PersistenceManagerFactory pmf;

// Class under test.
Dao dao;

@BeforeClass
public static void beforeAll() throws Exception {
  File mongoDir = new File(
      System.getProperty("java.io.tmpdir"),
      "mongodb-" + System.currentTimeMillis());
  mongoDir.deleteOnExit();
  mongod = Runtime.getRuntime().exec(String.format(
      "/bin/sh -c mongod --dbpath=%s --port=%d",
      mongoDir.getAbsolutePath(),
      PORT));
  LOG.info("Mongodb using {} on port {}.", mongoDir.getAbsolutePath(), PORT);
  Thread.sleep(1000);
  pmf = JDOHelper.getPersistenceManagerFactory("mongodbtest");
  LOG.info("DB connection URL: {}.", pmf.getConnectionURL());
}

@AfterClass
public static void afterAll() throws Exception {
  mongod.destroy();
}

@Before
public void setUp() throws Exception {
  dao = new Dao(pmf);
}

src/test/resources/META-INF/persistence.xml is like this: src / test / resources / META-INF / persistence.xml如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence ...>
  <persistence-unit name="mongodbtest">
    <properties>
      <property name="javax.jdo.PersistenceManagerFactoryClass"
          value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory" />
      <property name="javax.jdo.option.ConnectionURL" value="mongodb://localhost:100001/contacts"/>
      <property name="javax.jdo.option.RetainValues" value="true"/>
      <property name="datanucleus.autoCreateSchema" value="true" />
      <property name="datanucleus.validateTables" value="false" />
      <property name="datanucleus.validateConstraints" value="false" />
      <property name="datanucleus.storeManagerType" value="mongodb" />
    </properties>
  </persistence-unit>
</persistence>

And finally I execute my unit test with mvn clean test and that alone will work until I add an actual test that attempts save data. 最后,我使用mvn clean test执行单元测试,只有在添加尝试保存数据的实际测试之前,该单元测试才能起作用。 I get the following error: 我收到以下错误:

Mongodb using /var/folders/00/0l550000h01000cxqpysvccm002cmm/T/mongodb-1373820849219 on port 100001.
DB connection URL: mongodb://localhost:100001/contacts.
Jul 14, 2013 12:54:10 PM com.mongodb.DBTCPConnector initDirectConnection
WARNING: Exception executing isMaster command on localhost/127.0.0.1:27017
java.io.IOException: couldn't connect to [localhost/127.0.0.1:27017] bc:java.net.ConnectException: Connection refused
    at com.mongodb.DBPort._open(DBPort.java:214)
    at com.mongodb.DBPort.go(DBPort.java:107)

...

Jul 14, 2013 12:54:10 PM com.mongodb.DBTCPConnector initDirectConnection
WARNING: Exception executing isMaster command on localhost/127.0.0.1:27017
java.io.IOException: couldn't connect to [localhost/127.0.0.1:27017] bc:java.net.ConnectException: Connection refused
    at com.mongodb.DBPort._open(DBPort.java:214)
    at com.mongodb.DBPort.go(DBPort.java:107)

...

ul 14, 2013 12:54:10 PM com.mongodb.DBPortPool gotError
WARNING: emptying DBPortPool to localhost/127.0.0.1:27017 b/c of error
java.io.IOException: couldn't connect to [localhost/127.0.0.1:27017] bc:java.net.ConnectException: Connection refused
    at com.mongodb.DBPort._open(DBPort.java:214)
    at com.mongodb.DBPort.go(DBPort.java:107)

...

Jul 14, 2013 12:54:10 PM org.datanucleus.store.valuegenerator.AbstractGenerator obtainGenerationBlock
INFO: Error encountered allocating block of IDs : can't call something : localhost/127.0.0.1:27017//localhost:100001/contacts

127.0.0.1:27017 is mongodb's default settings but I have no idea why it's using that. 127.0.0.1:27017是mongodb的默认设置,但我不知道为什么要使用它。 I can see it's picking up the configs from my persistence.xml file so I'm confused. 我可以看到它正在从我的persistence.xml文件中提取配置,所以我很困惑。 The mongo docs say the connection string URL format is: mongo 文档说连接字符串URL格式为:

mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]

So far I've only been running this through maven because that's only as far as I got so far but another question I'll have eventually is how to run these unit tests in Eclipse. 到目前为止,我只是通过maven来运行它,因为到目前为止,我还剩下一个问题,那就是如何在Eclipse中运行这些单元测试。 I assume the byte code enhancement process has to happen for these tests to be run in Eclipse and I don't know how to set that up. 我认为必须在字节码增强过程中进行这些测试才能在Eclipse中运行,并且我不知道该如何设置。

I'm guessing I'm not the first person to want to do something like this though. 我猜我不是第一个想要做这样的事情的人。 Are there any standard practices for writing functional database tests in Java? 是否有使用Java编写功能数据库测试的标准实践? Am I going about it all wrong? 我要解决所有问题吗?

To answer my own question. 回答我自己的问题。 There were three issues: 存在三个问题:

1) The connection string should have been: 1)连接字符串应为:

mongo:/127.0.0.1/contacts

(note one less "/") (注意少一个“ /”)

2) I needed to add mongoDir.mkdir(); 2)我需要添加mongoDir.mkdir();

3) The command to start the server should be 3)启动服务器的命令应该是

String command = String.format(
    "/bin/sh -c mongod --dbpath=%s --port=%d", 
    mongoDir.getAbsolutePath(), 
    PORT);
Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", command });

I actually ended up creating a JUnit4 Runner for this so I could have the same database throughout all tests and left up to the individual tests to manage the state of that database. 实际上,我最终为此创建了一个JUnit4 Runner,因此我可以在所有测试中拥有相同的数据库,并让各个测试来管理该数据库的状态。

If you want to run a database instance to test against (that runs only for the time that your Maven build is running) then you might be interested in the Maven plugin that I wrote based on the flapdoodle Embedded Mongo API: 如果您想运行一个数据库实例进行测试(仅在您的Maven构建运行时运行),那么您可能会对我基于flappoodle Embedded Mongo API编写的Maven插件感兴趣:

embedmongo-maven-plugin embedmongo-maven-plugin

One benefit is that the plugin downloads the Mongo distribution automatically, so there's no need for people to install Mongo before they can run your Maven build. 好处之一是该插件会自动下载Mongo发行版,因此人们无需安装Mongo即可运行您的Maven构建。 It's also easy to move to a different Mongo version; 迁移到其他Mongo版本也很容易。 you just change the plugin configuration. 您只需更改插件配置即可。

Think about your goal I ran a simple main application that stores some junk data and retrieves it from mongodb and it looks ok, but I want to start writing proper unit tests. 考虑一下您的目标, I ran a simple main application that stores some junk data and retrieves it from mongodb and it looks ok, but I want to start writing proper unit tests.

If you work in team, you will find a problem with current source code. 如果您在团队中工作,您会发现当前的源代码有问题。 How if your another team member use staging db ? 如果您的另一个团队成员如何使用登台db? It will make your data useless, inconsistent and painful to reproduce bug related with db. 重现与db有关的错误,将使您的数据无用,不一致且痛苦。

I think the solution from @joelittlejohn is better. 我认为@joelittlejohn的解决方案更好。 Use embedded-mongo on your project. 在您的项目上使用Embedded-mongo。 Currently I use https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo for my project. 目前,我在项目中使用https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo You can do anything with your mongo without any hesitation. 您可以毫不犹豫地对mongo做任何事情。 Because it's just happen when you run test . 因为它只是在运行test时发生

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM