No SQL Unit - Devoxx 2012

86

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 of No SQL Unit - Devoxx 2012

Page 1: No SQL Unit - Devoxx 2012
Page 2: No SQL Unit - Devoxx 2012

NoSQLUnitTesting NoSQL Applications

Alex Soto BuenoComputer Engineerlordofthejars.com

@alexsotob

Page 3: No SQL Unit - Devoxx 2012

Carlo Strozzi

Introduction

Page 4: No SQL Unit - Devoxx 2012

Carlo Strozzi

Introduction

2000s

Page 5: No SQL Unit - Devoxx 2012

Carlo Strozzi

Introduction

2000s

Page 6: No SQL Unit - Devoxx 2012

Carlo Strozzi

Introduction

2000s

No Standard Way

Page 7: No SQL Unit - Devoxx 2012

About MeAlex Soto Bueno

Computer EngineerDiagnostic GrifolsTutor at UOCActive Blogger & Speaker

Page 8: No SQL Unit - Devoxx 2012

Theory

Page 9: No SQL Unit - Devoxx 2012

TheoryFIRST

Tests should Follow FIRST Rules

Page 10: No SQL Unit - Devoxx 2012

Theory

FastFIRST

Page 11: No SQL Unit - Devoxx 2012

Theory

IsolationFIRST

Page 12: No SQL Unit - Devoxx 2012

Theory

RepeatableFIRST

Page 13: No SQL Unit - Devoxx 2012

Theory

Self-ValidatingFIRST

Page 14: No SQL Unit - Devoxx 2012

Theory

TimelyFIRST

Page 15: No SQL Unit - Devoxx 2012

TheoryFIRST

Fast

Isolation

Repeatable

Self-Validating

Timely

Slow

Isolation

Repeatable

Self-Validating

Timely

Unit High

Page 16: No SQL Unit - Devoxx 2012

TheoryFIRST

Testing Persistence Layer May Break Isolated Rule

Page 17: No SQL Unit - Devoxx 2012

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(??));

}

Page 18: No SQL Unit - Devoxx 2012

TheoryFIRST

DBUnit

Page 19: No SQL Unit - Devoxx 2012

TheoryFIRST

DBUnit

NoSQLUnit

Page 20: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Manage Lifecycle

Page 21: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Manage Lifecycle

Maintain Database State

Page 22: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Manage Lifecycle

Maintain Database State

Standardize Tests

Page 23: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Two Groups JUnit Rules

Page 24: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Two Groups JUnit Rules

Two Annotations

Page 25: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

First Group:Start and Stop NoSQL Engine

Page 26: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Second Group:Connection to Databases

Page 27: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

@UsingDataSet for Seeding Contents

Page 28: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

@ShouldMatchDataSet for Verifying Contents

Page 29: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Start

Page 30: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Start Clean

Page 31: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Start Clean

Populate

Page 32: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Start Clean

PopulateExecute

Page 33: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Start Clean

PopulateExecute

Verify

Page 34: No SQL Unit - Devoxx 2012

TheoryNoSQLUnit

Start Clean

PopulateExecute

Verify Stop

Page 35: No SQL Unit - Devoxx 2012

Action

Page 36: No SQL Unit - Devoxx 2012

Action

Page 37: No SQL Unit - Devoxx 2012

Action

Embedded InMemory Redis

com.lordofthejars.nosqlunit.redis.EmbeddedRedis

com.lordofthejars.nosqlunit.redis.ManagedRedis

Managed Redis

Page 38: No SQL Unit - Devoxx 2012

Redis Connection

com.lordofthejars.nosqlunit.redis.RedisRule

Action

Page 39: No SQL Unit - Devoxx 2012

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"}]}] }

]

Page 40: No SQL Unit - Devoxx 2012

Action

Demo

Page 41: No SQL Unit - Devoxx 2012

Action

Page 42: No SQL Unit - Devoxx 2012

Action

Page 43: No SQL Unit - Devoxx 2012

Action

Embedded Cassandra

com.lordofthejars.nosqlunit.cassandra.EmbeddedCassandra

com.lordofthejars.nosqlunit.cassandra.ManagedCassandra

Managed Cassandra

Page 44: No SQL Unit - Devoxx 2012

Cassandra Connection

com.lordofthejars.nosqlunit.cassandra.CassandraRule

Action

Page 45: No SQL Unit - Devoxx 2012

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" }] }

]

Page 46: No SQL Unit - Devoxx 2012

Action

Page 47: No SQL Unit - Devoxx 2012

Action

Embedded HBase

com.lordofthejars.nosqlunit.hbase.EmbeddedHBase

com.lordofthejars.nosqlunit.hbase.ManagedHBase

Managed HBase

Page 48: No SQL Unit - Devoxx 2012

HBase Connection

com.lordofthejars.nosqlunit.hbase.HBaseRule

Action

Page 49: No SQL Unit - Devoxx 2012

Action

"name" : "tablename", "columnFamilies" : [{ "name" : "columnFamilyName", "rows" : [{ "key" : "key1", "columns" : [{ "name" : "columnName", "value" : "columnValue" }, ... ] }, ... ] }, ... ]

Page 50: No SQL Unit - Devoxx 2012

Action

Page 51: No SQL Unit - Devoxx 2012

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

Page 52: No SQL Unit - Devoxx 2012

Neo4j Connection

com.lordofthejars.nosqlunit.neo4j.Neo4jRule

Action

Page 53: No SQL Unit - Devoxx 2012

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>

Page 54: No SQL Unit - Devoxx 2012

Action

Demo

Page 55: No SQL Unit - Devoxx 2012

Action

Page 56: No SQL Unit - Devoxx 2012

Action

Page 57: No SQL Unit - Devoxx 2012

Action

Embedded InMemory MongoDB

com.lordofthejars.nosqlunit.mongodb.InMemoryMongoDb

com.lordofthejars.nosqlunit.mongodb.ManagedMongoDb

Managed MongoDB

Page 58: No SQL Unit - Devoxx 2012

MongoDB Connection

com.lordofthejars.nosqlunit.mongodb.MongoDbRule

Action

Page 59: No SQL Unit - Devoxx 2012

Action

{ "name_collection1": [ { "attribute_1":"value1", "attribute_2":"value2" }, { "attribute_3":2, "attribute_4":"value4" } ], "name_collection2": [ ... ], ....}

Page 60: No SQL Unit - Devoxx 2012

More

Page 61: No SQL Unit - Devoxx 2012

ActionNoSQLUnit

NoSQLUnit is Ready for the clouds

No lifecycle management

Page 62: No SQL Unit - Devoxx 2012

Action

Demo

NoSQLUnit

Page 63: No SQL Unit - Devoxx 2012

ActionNoSQLUnit

Acceptance Tests Cloud

Page 64: No SQL Unit - Devoxx 2012

ActionNoSQLUnit

NoSQL system may be polyglot

Populating different data in parallel

Page 65: No SQL Unit - Devoxx 2012

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() {...}

Page 66: No SQL Unit - Devoxx 2012

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() {...}

Page 67: No SQL Unit - Devoxx 2012

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() {...}

Page 68: No SQL Unit - Devoxx 2012

ActionNoSQLUnit

Partial Support for JSR-330

@Inject

@Named

Page 69: No SQL Unit - Devoxx 2012

ActionNoSQLUnit

Rulepublic final MongoDbRule mongoDb = newMongoDbRule().defaultManagedMongoDb(“test”, this);

@Injectprivate Mongo mongo;

Page 70: No SQL Unit - Devoxx 2012

Action

Flashback

NoSQLUnit

Page 71: No SQL Unit - Devoxx 2012

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

Page 72: No SQL Unit - Devoxx 2012

Action

Hibernate MongoDB - name propertyHibernate

Page 73: No SQL Unit - Devoxx 2012

What’s Coming

Page 74: No SQL Unit - Devoxx 2012

What’s ComingEngines

Page 75: No SQL Unit - Devoxx 2012

What’s ComingIntegration

Page 76: No SQL Unit - Devoxx 2012

What’s ComingIntegration

https://github.com/lordofthejars/nosql-unit/issues

Page 77: No SQL Unit - Devoxx 2012

Conclusions

Page 78: No SQL Unit - Devoxx 2012

Conclusions

Hard and Tedious JobSpiderman way

Page 79: No SQL Unit - Devoxx 2012

ConclusionsSpiderman way

Page 80: No SQL Unit - Devoxx 2012

ConclusionsSpiderman way

Page 81: No SQL Unit - Devoxx 2012

ConclusionsSpiderman way

Page 82: No SQL Unit - Devoxx 2012

Thank you

Page 83: No SQL Unit - Devoxx 2012

Questions

Questions

Page 84: No SQL Unit - Devoxx 2012

NoSQLUnitTesting NoSQL Applications

Alex Soto BuenoComputer Engineerlordofthejars.com

@alexsotobUmi no kanatani wa mou sagasanai, Kagayaku monowa itsumo kokoni (Itsumo Nando De Mo)

Page 85: No SQL Unit - Devoxx 2012

NoSQLUnitTesting NoSQL Applications

Alex Soto BuenoComputer Engineerlordofthejars.com

@alexsotob

Page 86: No SQL Unit - Devoxx 2012

CC Photos