No SQL Unit - Devoxx 2012

Post on 15-Jan-2015

205 views 2 download

Tags:

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