no sql unit - devoxx 2012
DESCRIPTION
Unit tests should follow the FIRST rules (Fast, Isolated, Repeatable, Self-Validated and Timely). When persistence layer is under test, fast and isolated rules are the most violated. For relational database management systems, embedded databases and DbUnit framework exist to help us to not break them, but there is no like DBUnit framework for heterogeneous NoSQL systems. NoSQLUnit aids us to not break these rules by providing a JUnit extension which helps us to manage lifecycle of NoSQL systems and also it takes care of maintaining databases into known state. NoSQLUnit can be used during unit tests, but also in high level tests like integration or acceptance tests.TRANSCRIPT
NoSQLUnitTesting NoSQL Applications
Alex Soto BuenoComputer Engineerlordofthejars.com
@alexsotob
Carlo Strozzi
Introduction
Carlo Strozzi
Introduction
2000s
Carlo Strozzi
Introduction
2000s
Carlo Strozzi
Introduction
2000s
No Standard Way
About MeAlex Soto Bueno
Computer EngineerDiagnostic GrifolsTutor at UOCActive Blogger & Speaker
Theory
TheoryFIRST
Tests should Follow FIRST Rules
Theory
FastFIRST
Theory
IsolationFIRST
Theory
RepeatableFIRST
Theory
Self-ValidatingFIRST
Theory
TimelyFIRST
TheoryFIRST
Fast
Isolation
Repeatable
Self-Validating
Timely
Slow
Isolation
Repeatable
Self-Validating
Timely
Unit High
TheoryFIRST
Testing Persistence Layer May Break Isolated Rule
TheoryFIRSTpublic void savePhone(Phone phone) {
...}
@Testpublic void should_insert_phone() {phoneService.save(new Phone());
}
@Testpublic void should_count_phones() {int numberOfPhones = phoneService.count(); assertThat(numberOfPhones, equalTo(??));
}
TheoryFIRST
DBUnit
TheoryFIRST
DBUnit
NoSQLUnit
TheoryNoSQLUnit
Manage Lifecycle
TheoryNoSQLUnit
Manage Lifecycle
Maintain Database State
TheoryNoSQLUnit
Manage Lifecycle
Maintain Database State
Standardize Tests
TheoryNoSQLUnit
Two Groups JUnit Rules
TheoryNoSQLUnit
Two Groups JUnit Rules
Two Annotations
TheoryNoSQLUnit
First Group:Start and Stop NoSQL Engine
TheoryNoSQLUnit
Second Group:Connection to Databases
TheoryNoSQLUnit
@UsingDataSet for Seeding Contents
TheoryNoSQLUnit
@ShouldMatchDataSet for Verifying Contents
TheoryNoSQLUnit
Start
TheoryNoSQLUnit
Start Clean
TheoryNoSQLUnit
Start Clean
Populate
TheoryNoSQLUnit
Start Clean
PopulateExecute
TheoryNoSQLUnit
Start Clean
PopulateExecute
Verify
TheoryNoSQLUnit
Start Clean
PopulateExecute
Verify Stop
Action
Action
Action
Embedded InMemory Redis
com.lordofthejars.nosqlunit.redis.EmbeddedRedis
com.lordofthejars.nosqlunit.redis.ManagedRedis
Managed Redis
Redis Connection
com.lordofthejars.nosqlunit.redis.RedisRule
Action
Action
"data":[ {"simple": [{"key":"key1", "value":"value1"}] }, {"list": [{"key":"key3","values":[{"value":"value3"},{"value":"value4"}]}] }, {"sortset": [{"key":"key4","values":[ {"score":2, "value":"value5" },{"score":3, "value":1 }}]
}] }, {"hash": [{"key":"user","values":[{"field":"name", "value":"alex"},]}] }, {"set":[{"key":"key3","values":[{"value":"value3"},{"value":"value4"}]}] }
]
Action
Demo
Action
Action
Action
Embedded Cassandra
com.lordofthejars.nosqlunit.cassandra.EmbeddedCassandra
com.lordofthejars.nosqlunit.cassandra.ManagedCassandra
Managed Cassandra
Cassandra Connection
com.lordofthejars.nosqlunit.cassandra.CassandraRule
Action
Action"name" : "keyspaceName","columnFamilies" : [{ "name" : "columnFamilyName", "rows" : [{ "key" : "key10", "columns" : [{ "name" : "name11", "value" : "value11" }] },
{ "name" : "otherColumnFamilyName", "type" : "SUPER", "rows" : [{ "key" : "10", "superColumns" : [{ "name" : "1100", "columns" : [{ "name" : "1110", "value" : "1110" }] }
]
Action
Action
Embedded HBase
com.lordofthejars.nosqlunit.hbase.EmbeddedHBase
com.lordofthejars.nosqlunit.hbase.ManagedHBase
Managed HBase
HBase Connection
com.lordofthejars.nosqlunit.hbase.HBaseRule
Action
Action
"name" : "tablename", "columnFamilies" : [{ "name" : "columnFamilyName", "rows" : [{ "key" : "key1", "columns" : [{ "name" : "columnName", "value" : "columnValue" }, ... ] }, ... ] }, ... ]
Action
ActionEmbedded InMemory Neo4j
com.lordofthejars.nosqlunit.neo4j.InMemoryNeo4j
com.lordofthejars.nosqlunit.neo4j.EmbeddedNeo4j
Embedded Neo4j
Managed Wrapped Neo4j
com.lordofthejars.nosqlunit.neo4j.ManagedWrappingNeoServer
Managed Neo4j
com.lordofthejars.nosqlunit.neo4j.ManagedNeoServer
Neo4j Connection
com.lordofthejars.nosqlunit.neo4j.Neo4jRule
Action
Action
<?xml version="1.0" encoding="UTF-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns"> <key id="attr1" for="edge" attr.name="attr1" attr.type="float"/> <key id="attr2" for="node" attr.name="attr2" attr.type="string"/> <graph id="G" edgedefault="directed"> <node id="1"> <data key="attr2">value1</data> </node> <node id="2"> <data key="attr2">value2</data> </node> <edge id="7" source="1" target="2" label="label1"> <data key="attr1">float</data> </edge> </graph></graphml>
Action
Demo
Action
Action
Action
Embedded InMemory MongoDB
com.lordofthejars.nosqlunit.mongodb.InMemoryMongoDb
com.lordofthejars.nosqlunit.mongodb.ManagedMongoDb
Managed MongoDB
MongoDB Connection
com.lordofthejars.nosqlunit.mongodb.MongoDbRule
Action
Action
{ "name_collection1": [ { "attribute_1":"value1", "attribute_2":"value2" }, { "attribute_3":2, "attribute_4":"value4" } ], "name_collection2": [ ... ], ....}
More
ActionNoSQLUnit
NoSQLUnit is Ready for the clouds
No lifecycle management
Action
Demo
NoSQLUnit
ActionNoSQLUnit
Acceptance Tests Cloud
ActionNoSQLUnit
NoSQL system may be polyglot
Populating different data in parallel
ActionNoSQLUnit
private final Neo4jConfiguration neo4jConfiguration = newManagedNeoServerConfiguration().connectionIdentifier("neo4j").build();
@Rulepublic final Neo4jRule neo4jRule = newNeo4jRule().configure(neo4jConfiguration).build();
private final RedisConfiguration redisConfiguration = newManagedRedisConfiguration().connectionIdentifier("redis").build();
@Rulepublic final RedisRule redisRule = newRedisRule().configure(redisConfiguration).build();
@Test@UsingDataSet(withSelectiveLocations = {! @Selective(identifier = "neo4j", locations = "matrix.xml"),! @Selective(identifier = "redis", locations = "matrix.json") }, ! loadStrategy = LoadStrategyEnum.CLEAN_INSERT)public void cached_friends_should_be_returned() {...}
ActionNoSQLUnit
private final Neo4jConfiguration neo4jConfiguration = newManagedNeoServerConfiguration().connectionIdentifier("neo4j").build();
@Rulepublic final Neo4jRule neo4jRule = newNeo4jRule().configure(neo4jConfiguration).build();
private final RedisConfiguration redisConfiguration = newManagedRedisConfiguration().connectionIdentifier("redis").build();
@Rulepublic final RedisRule redisRule = newRedisRule().configure(redisConfiguration).build();
@Test@UsingDataSet(withSelectiveLocations = {! @Selective(identifier = "neo4j", locations = "matrix.xml"),! @Selective(identifier = "redis", locations = "matrix.json") }, ! loadStrategy = LoadStrategyEnum.CLEAN_INSERT)public void cached_friends_should_be_returned() {...}
ActionNoSQLUnit
private final Neo4jConfiguration neo4jConfiguration = newManagedNeoServerConfiguration().connectionIdentifier("neo4j").build();
@Rulepublic final Neo4jRule neo4jRule = newNeo4jRule().configure(neo4jConfiguration).build();
private final RedisConfiguration redisConfiguration = newManagedRedisConfiguration().connectionIdentifier("redis").build();
@Rulepublic final RedisRule redisRule = newRedisRule().configure(redisConfiguration).build();
@Test@UsingDataSet(withSelectiveLocations = {! @Selective(identifier = "neo4j", locations = "matrix.xml"),! @Selective(identifier = "redis", locations = "matrix.json") }, ! loadStrategy = LoadStrategyEnum.CLEAN_INSERT)public void cached_friends_should_be_returned() {...}
ActionNoSQLUnit
Partial Support for JSR-330
@Inject
@Named
ActionNoSQLUnit
Rulepublic final MongoDbRule mongoDb = newMongoDbRule().defaultManagedMongoDb(“test”, this);
@Injectprivate Mongo mongo;
Action
Flashback
NoSQLUnit
Action
Spring Data MongoDB - _class attribute
Spring Data Redis - Serializer/OXM/JSON
Spring Data HBase - RowMapper interface
Spring Data Neo4j - __type__ attribute
Spring Data Cassandra - EntityWritter interface
Spring Data
Action
Hibernate MongoDB - name propertyHibernate
What’s Coming
What’s ComingEngines
What’s ComingIntegration
What’s ComingIntegration
https://github.com/lordofthejars/nosql-unit/issues
Conclusions
Conclusions
Hard and Tedious JobSpiderman way
ConclusionsSpiderman way
ConclusionsSpiderman way
ConclusionsSpiderman way
Thank you
Questions
Questions
NoSQLUnitTesting NoSQL Applications
Alex Soto BuenoComputer Engineerlordofthejars.com
@alexsotobUmi no kanatani wa mou sagasanai, Kagayaku monowa itsumo kokoni (Itsumo Nando De Mo)
NoSQLUnitTesting NoSQL Applications
Alex Soto BuenoComputer Engineerlordofthejars.com
@alexsotob
CC Photos