diff --git a/pom.xml b/pom.xml
index e157e32..d012168 100644
--- a/pom.xml
+++ b/pom.xml
@@ -58,6 +58,12 @@
             <version>5.10.0</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>4.11.0</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/src/main/java/org/javawebstack/abstractdata/collector/AbstractArrayCollector.java b/src/main/java/org/javawebstack/abstractdata/collector/AbstractArrayCollector.java
index f9cd104..07b2d76 100644
--- a/src/main/java/org/javawebstack/abstractdata/collector/AbstractArrayCollector.java
+++ b/src/main/java/org/javawebstack/abstractdata/collector/AbstractArrayCollector.java
@@ -46,7 +46,6 @@ public Function<List<AbstractElement>, AbstractArray> finisher() {
 
     public Set<Characteristics> characteristics() {
         Set<Characteristics> characteristics = new HashSet<>();
-        characteristics.add(Characteristics.UNORDERED);
         return characteristics;
     }
 
diff --git a/src/main/java/org/javawebstack/abstractdata/json/JsonDumper.java b/src/main/java/org/javawebstack/abstractdata/json/JsonDumper.java
index a8097f3..f33abf5 100644
--- a/src/main/java/org/javawebstack/abstractdata/json/JsonDumper.java
+++ b/src/main/java/org/javawebstack/abstractdata/json/JsonDumper.java
@@ -83,7 +83,7 @@ private List<String> dumpLines(AbstractElement element) {
             }
             return lines;
         }
-        return new ArrayList<>();
+        throw new IllegalArgumentException("Unknown element type"); // Should be unreachable
     }
 
     private static String escape(String s) {
diff --git a/src/test/java/org/javawebstack/abstractdata/collector/AbstractArrayCollectorTest.java b/src/test/java/org/javawebstack/abstractdata/collector/AbstractArrayCollectorTest.java
new file mode 100644
index 0000000..1d1c4a5
--- /dev/null
+++ b/src/test/java/org/javawebstack/abstractdata/collector/AbstractArrayCollectorTest.java
@@ -0,0 +1,20 @@
+package org.javawebstack.abstractdata.collector;
+
+import org.javawebstack.abstractdata.AbstractArray;
+import org.javawebstack.abstractdata.AbstractPrimitive;
+import org.junit.jupiter.api.Test;
+import java.util.stream.Stream;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class AbstractArrayCollectorTest {
+
+    @Test
+    public void testCollection() {
+        AbstractArray array = Stream.of("a", "b", "c").parallel().collect(new AbstractArrayCollector<>(AbstractPrimitive::new));
+        assertEquals(3, array.size());
+        assertEquals("a", array.string(0));
+        assertEquals("b", array.string(1));
+        assertEquals("c", array.string(2));
+    }
+
+}
diff --git a/src/test/java/org/javawebstack/abstractdata/collector/AbstractObjectCollectorTest.java b/src/test/java/org/javawebstack/abstractdata/collector/AbstractObjectCollectorTest.java
new file mode 100644
index 0000000..c79416a
--- /dev/null
+++ b/src/test/java/org/javawebstack/abstractdata/collector/AbstractObjectCollectorTest.java
@@ -0,0 +1,21 @@
+package org.javawebstack.abstractdata.collector;
+
+import org.javawebstack.abstractdata.AbstractObject;
+import org.javawebstack.abstractdata.AbstractPrimitive;
+import org.junit.jupiter.api.Test;
+
+import java.util.stream.Stream;
+import static org.junit.jupiter.api.Assertions.*;
+
+public class AbstractObjectCollectorTest {
+
+    @Test
+    public void testCollection() {
+        AbstractObject object = Stream.of("a", "bc", "def").parallel().collect(new AbstractObjectCollector<>(s -> s, s -> new AbstractPrimitive(s.length())));
+        assertEquals(3, object.size());
+        assertEquals(1, object.number("a"));
+        assertEquals(2, object.number("bc"));
+        assertEquals(3, object.number("def"));
+    }
+
+}
diff --git a/src/test/java/org/javawebstack/abstractdata/json/JsonDumperTest.java b/src/test/java/org/javawebstack/abstractdata/json/JsonDumperTest.java
new file mode 100644
index 0000000..1134be7
--- /dev/null
+++ b/src/test/java/org/javawebstack/abstractdata/json/JsonDumperTest.java
@@ -0,0 +1,116 @@
+package org.javawebstack.abstractdata.json;
+
+import org.javawebstack.abstractdata.*;
+import org.junit.jupiter.api.Test;
+import static org.mockito.Mockito.*;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class JsonDumperTest {
+
+    @Test
+    public void testDumpJavaNull() {
+        assertEquals("null", new JsonDumper().dump(null));
+    }
+
+    @Test
+    public void testDumpNull() {
+        assertEquals("null", new JsonDumper().dump(AbstractNull.VALUE));
+    }
+
+    @Test
+    public void testDumpString() {
+        assertEquals("\"abc\"", new JsonDumper().dump(new AbstractPrimitive("abc")));
+    }
+
+    @Test
+    public void testDumpNumber() {
+        assertEquals("123.456", new JsonDumper().dump(new AbstractPrimitive(123.456)));
+    }
+
+    @Test
+    public void testDumpBoolean() {
+        assertEquals("true", new JsonDumper().dump(new AbstractPrimitive(true)));
+        assertEquals("false", new JsonDumper().dump(new AbstractPrimitive(false)));
+    }
+
+    @Test
+    public void testDumpObject() {
+        assertEquals("{\"a\":1,\"b\":2}", new JsonDumper().dump(new AbstractObject().set("a", 1).set("b", 2)));
+    }
+
+    @Test
+    public void testDumpArray() {
+        assertEquals("[1,2,3]", new JsonDumper().dump(new AbstractArray().add(1).add(2).add(3)));
+    }
+
+    @Test
+    public void testEscapeStringEscapeSeq() {
+        Map<String, String> escapes = new HashMap<>();
+        escapes.put("\"", "\\\"");
+        escapes.put("\\", "\\\\");
+        escapes.put("\b", "\\b");
+        escapes.put("\f", "\\f");
+        escapes.put("\n", "\\n");
+        escapes.put("\r", "\\r");
+        escapes.put("\t", "\\t");
+        escapes.put("\0", "\\0");
+        escapes.put("/", "\\/");
+        for(String c : escapes.keySet()) {
+            assertEquals("\"" + escapes.get(c) + "\"", new JsonDumper().dump(new AbstractPrimitive(c)));
+        }
+    }
+
+    @Test
+    public void testEscapeStringUnicode() {
+        assertEquals("\"\\u001F\"", new JsonDumper().dump(new AbstractPrimitive("\u001F")));
+    }
+
+    @Test
+    public void testPrettyFlag() {
+        AbstractObject o = new AbstractObject()
+                .set("a", 1)
+                .set("b", new AbstractArray().add("a").add("b"));
+        String expectedNonPretty = "{\"a\":1,\"b\":[\"a\",\"b\"]}";
+        String expectedPretty = "{\n    \"a\": 1,\n    \"b\": [\n        \"a\",\n        \"b\"\n    ]\n}";
+        assertEquals(expectedNonPretty, new JsonDumper().dump(o));
+        assertEquals(expectedPretty, new JsonDumper().setPretty(true).dump(o));
+    }
+
+    @Test
+    public void testIndent() {
+        AbstractObject o = new AbstractObject()
+                .set("a", 1)
+                .set("b", new AbstractArray().add("a").add("b"));
+        String defaultIndent = "    ";
+        String shortIndent = "  ";
+        Function<String, String> expectedFn = indent -> "{\n" + indent + "\"a\": 1,\n" + indent + "\"b\": [\n" + indent + indent + "\"a\",\n" + indent + indent + "\"b\"\n" + indent + "]\n}";
+        assertEquals(expectedFn.apply(defaultIndent), new JsonDumper().setPretty(true).dump(o));
+        assertEquals(expectedFn.apply(shortIndent), new JsonDumper().setIndent(shortIndent).setPretty(true).dump(o));
+    }
+
+    @Test
+    public void testNoNewlineOnEmptyObject() {
+        AbstractObject object = new AbstractObject().set("a", new AbstractObject());
+        String expected = "{\n    \"a\": {}\n}";
+        assertEquals(expected, new JsonDumper().setPretty(true).dump(object));
+    }
+
+    @Test
+    public void testNoNewlineOnEmptyArray() {
+        AbstractObject object = new AbstractObject().set("a", new AbstractArray());
+        String expected = "{\n    \"a\": []\n}";
+        assertEquals(expected, new JsonDumper().setPretty(true).dump(object));
+    }
+
+    @Test
+    public void testDumpUnknownType() {
+        AbstractElement e = mock(AbstractElement.class);
+        assertThrows(IllegalArgumentException.class, () -> new JsonDumper().dump(e));
+    }
+
+}