单元测试是一种验证应用程序中可测试的最小部分的方法。 单元测试必须遵循FIRST规则; 这些是快速,隔离,可重复,自我验证和及时的。
考虑到没有持久层(典型的关系数据库或新的NoSQL数据库)的JEE应用程序很奇怪,因此编写持久层的单元测试也应该很有趣。 当我们编写持久层的单元测试时,我们应该专注于不破坏FIRST规则的两个主要概念,即快速规则和隔离规则。
如果他们不访问网络或文件系统,则我们的测试将很快,并且在持久性系统的情况下,网络和文件系统是最常用的资源。 对于RDBMS (SQL),存在许多Java内存数据库,例如Apache Derby , H2或HSQLDB 。 顾名思义,这些数据库已嵌入到您的程序中,并且数据存储在内存中,因此您的测试仍然很快。 问题在于NoSQL系统,因为它们具有异质性。 一些系统使用Document方法(例如MongoDb ),其他Column(例如Hbase )或Graph(例如Neo4J )工作。 因此,供应商应提供内存模式,没有通用的解决方案。
我们的测试必须与自己隔离。 一种测试方法修改另一种测试方法的结果是不可接受的。 在持久性测试的情况下,当前一个测试方法向数据库插入一个条目,而下一个测试方法执行找到更改时,就会发生这种情况。 因此,在执行每个测试之前,应该以已知状态找到数据库。 请注意,如果您的测试发现数据库处于已知状态,则测试将是可重复的,如果测试断言取决于先前的测试执行,则每个执行都是唯一的。 对于RDBMS之类的同类系统,存在DBUnit来在每次执行之前将数据库保持在已知状态。 但是还没有用于异构NoSQL系统的DBUnit框架。
NoSQLUnit通过提供一个JUnit扩展来解决此问题,该扩展可以帮助我们管理NoSQL系统的生命周期,并有助于将数据库维护为已知状态。
NoSQLUnit
NoSQLUnit是一个JUnit扩展,它使使用NoSQL后端的系统的编写单元测试和集成测试更加容易,它由两组规则和一组注释组成。
第一组规则是负责管理数据库生命周期的规则 ; 每个受支持的后端都有两个。
- 第一个(如果可能的话)它是内存模式。 此模式负责以“内存中”模式启动和停止数据库系统。 此模式通常在单元测试执行期间使用。
- 第二个是托管模式。 此模式负责启动NoSQL服务器,但作为远程进程(在本地计算机中)并停止它。 通常在集成测试执行期间使用。
第二组规则是负责将数据库保持为已知状态的规则 。 每个受支持的后端都有自己的后端,可以理解为与已定义数据库的连接,该数据库将用于执行所需的操作以维护系统的稳定性。
请注意,由于NoSQL数据库是异构数据库,因此每个系统都需要自己的实现。
最后提供了两个注释, @UsingDataSet和@ShouldMatchDataSet (非常感谢Arquillian的名字),用于指定数据集和预期数据集的位置。
MongoDb示例
现在,我将解释一个非常简单的示例,说明如何使用NoSQLUnit,要全面了解所提供的所有功能,请阅读链接中的文档或以pdf格式下载 。
要使用MongoDB的使用NoSQLUnit你只需要添加下一依赖性:
<dependency><groupId>com.lordofthejars<groupId><artifactId>nosqlunit-mongodb<artifactId><version>0.3.0<version><dependency>
第一步是定义测试所需的生命周期管理策略。 根据您要实施的测试类型(单元测试,集成测试,部署测试等),您将需要内存方式, 托管方式或远程方式。
对于此示例,我们将使用通过ManagedMongoDb规则使用托管方法),但请注意,还支持内存中 MongoDb管理(请参见文档说明)。
下一步是配置Mongodb规则, 该规则负责通过插入和删除定义的数据集来将MongoDb数据库保持在已知状态。 您必须注册MongoDbRule JUnit规则类,该类需要一个配置参数,其中包含主机,端口或数据库名称之类的信息。
为了简化开发人员的生活并使代码更易读,可以使用流畅的界面来创建这些配置对象。
让我们看一下代码:
首先是一个简单的POJO类,它将用作模型类:
public class Book {private String title;private int numberOfPages;public Book(String title, int numberOfPages) {super();this.title = title;this.numberOfPages = numberOfPages;}public void setTitle(String title) {this.title = title;}public void setNumberOfPages(int numberOfPages) {this.numberOfPages = numberOfPages;}public String getTitle() {return title;}public int getNumberOfPages() {return numberOfPages;}}
下一业务类负责管理对MongoDb服务器的访问:
public class BookManager {private static final Logger LOGGER = LoggerFactory.getLogger(BookManager.class);private static final MongoDbBookConverter MONGO_DB_BOOK_CONVERTER = new MongoDbBookConverter();private static final DbObjectBookConverter DB_OBJECT_BOOK_CONVERTER = new DbObjectBookConverter();private DBCollection booksCollection;public BookManager(DBCollection booksCollection) {this.booksCollection = booksCollection;}public void create(Book book) {DBObject dbObject = MONGO_DB_BOOK_CONVERTER.convert(book);booksCollection.insert(dbObject);}}
现在该进行测试了。 在下一个测试中,我们将验证一本书是否已正确插入数据库。
package com.lordofthejars.nosqlunit.demo.mongodb;public class WhenANewBookIsCreated {@ClassRulepublic static ManagedMongoDb managedMongoDb = newManagedMongoDbRule().mongodPath('optmongo').build();@Rulepublic MongoDbRule remoteMongoDbRule = new MongoDbRule(mongoDb().databaseName('test').build());@Test@UsingDataSet(locations='initialData.json', loadStrategy=LoadStrategyEnum.CLEAN_INSERT)@ShouldMatchDataSet(location='expectedData.json')public void book_should_be_inserted_into_repository() {BookManager bookManager = new BookManager(MongoDbUtil.getCollection(Book.class.getSimpleName()));Book book = new Book('The Lord Of The Rings', 1299);bookManager.create(book);}}
看到首先,我们正在使用ClassRule注释创建与MongoDb服务器的托管连接。 在这种情况下,我们将以编程方式配置MongoDb路径,但也可以从MONGO_HOME环境变量进行设置。 请参见此处所有可用参数的完整说明。
加载测试时将执行此规则 ,并将启动MongoDb实例。 执行完所有测试后,还将关闭服务器。
Next Rule在任何测试方法之前执行,负责将数据库保持在已知状态。 注意,我们仅配置工作数据库,在本例中为测试数据库。
最后,我们用@UsingDataSet注释方法测试,指示执行每个测试之前要在哪里找到要插入的数据,并@ShouldMatchDataSet定位预期的数据集。
{'Book':[{'title':'The Hobbit','numberOfPages':293}]}
{'Book':[{'title':'The Hobbit','numberOfPages':293},{'title':'The Lord Of The Rings','numberOfPages':1299}]}
我们正在设置文件initialData.json初始数据集位于classpath中COM / lordofthejars / nosqlunit /演示/ MongoDB的/ initialData.json和预期的数据集叫expectedData.json。
最后说明
虽然NoSQLUnit是在早期阶段,MongoDB中的部分几乎已经完成,在接下来的版本中的新功能,当然还有新的数据库将得到支持。 下一个NoSQL支持的引擎将是Neo4J , Cassandra , HBase和CouchDb 。
另请阅读文档 ,您将在此处找到对每个功能的完整说明。
最后,您的任何建议,任何建议或任何建议都将受到欢迎。
保持学习!
完整代码
参考: NoSQLUnit 0.3.0从我们的JCG合作伙伴 Alex Soto在“ 一个罐子统治所有”博客上发布。
翻译自: https://www.javacodegeeks.com/2012/06/nosqlunit-030-released.html