diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0c12a21cc6e40f8f77cfe4986e55a1da6ba8f767..15b69a405625d367bee895ae1ff039fc2dd585ce 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,13 +1,19 @@
 image: python:3
 
+before_script:
+ - pip install doxec numpy
+ - python3 setup.py install
+
 stages:
   - test
 
+unittest:
+    stage: test
+    script:
+      - python3 setup.py test 
 
 README:
     stage: test
     script:
-     - pip install doxec numpy
-     - python3 setup.py install
      - doxec README.md 
 
diff --git a/setup.py b/setup.py
index c9e35cb987db74638dcc5e873612976b0b26c1dc..0a9ca87b2dc206922100d7c636c5015d2c5c2e08 100644
--- a/setup.py
+++ b/setup.py
@@ -11,5 +11,6 @@ module1 = Extension('sortednp', language='c++',
 setup (name = 'sortednp',
        version = '0.0.0',
        install_requires=['numpy'],
+       test_suite='tests',
        description = 'Merge and intersect sorted numpy arrays.',
        ext_modules = [module1])
diff --git a/sortednpmodule.c b/sortednpmodule.c
index 13401a490668063d5c07159bf96b152976ed9eec..7dac6f1b8e03f6850e33402b5dab952d5fd16f3f 100644
--- a/sortednpmodule.c
+++ b/sortednpmodule.c
@@ -5,8 +5,9 @@
 
 static PyObject * sortednp_intersect(PyObject *self, PyObject *args) {
     PyObject *a, *b;
-    if (!PyArg_ParseTuple(args, "OO", &a, &b))
-         return NULL;
+
+    if (!PyArg_ParseTuple(args, "O!O!", &PyArray_Type, &a, &PyArray_Type, &b))
+        return NULL;
 
     a = PyArray_FROM_OF(a, NPY_ARRAY_CARRAY_RO);
     b = PyArray_FROM_OF(b, NPY_ARRAY_CARRAY_RO);
@@ -19,6 +20,7 @@ static PyObject * sortednp_intersect(PyObject *self, PyObject *args) {
     int nd_b = PyArray_NDIM(b);
 
     if (PyArray_NDIM(a) != 1 || PyArray_NDIM(b) != 1) {
+      PyErr_SetString(PyExc_ValueError, "Arguments can not be multi-dimensional.");
       return NULL;
     }
 
@@ -70,8 +72,8 @@ static PyObject * sortednp_intersect(PyObject *self, PyObject *args) {
 
 static PyObject * sortednp_merge(PyObject *self, PyObject *args) {
     PyObject *a, *b;
-    if (!PyArg_ParseTuple(args, "OO", &a, &b))
-         return NULL;
+    if (!PyArg_ParseTuple(args, "O!O!", &PyArray_Type, &a, &PyArray_Type, &b))
+        return NULL;
 
     a = PyArray_FROM_OF(a, NPY_ARRAY_CARRAY_RO);
     b = PyArray_FROM_OF(b, NPY_ARRAY_CARRAY_RO);
@@ -84,6 +86,7 @@ static PyObject * sortednp_merge(PyObject *self, PyObject *args) {
     int nd_b = PyArray_NDIM(b);
 
     if (PyArray_NDIM(a) != 1 || PyArray_NDIM(b) != 1) {
+      PyErr_SetString(PyExc_ValueError, "Arguments can not be multi-dimensional.");
       return NULL;
     }
 
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/test_intersect.py b/tests/test_intersect.py
new file mode 100644
index 0000000000000000000000000000000000000000..ae704899d1b6fb3b5f5623c30d1d01812ac83013
--- /dev/null
+++ b/tests/test_intersect.py
@@ -0,0 +1,237 @@
+
+from abc import ABCMeta, abstractmethod
+import unittest
+import numpy as np
+
+import sortednp as snp
+
+class IntersectBase(metaclass=ABCMeta):
+    """
+    Define general test cases for the intersect method. Sub-classes need to
+    implement have to overwrite the dtype method.
+    """
+
+    @abstractmethod
+    def get_dtype(self):
+        """
+        Returns the numpy data type, which should be used for all tests.
+        """
+        pass
+    
+    def test_simple_middle(self):
+        """
+        Check that intersect returns only element, which are present in both
+        non-empty input arrays. The common elements are neither at the
+        beginning nor at the end of the arrays.
+        """
+        a = np.array([2, 3, 6, 7, 9], dtype=self.get_dtype())
+        b = np.array([1, 3, 7, 8, 10], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+
+        self.assertEqual(list(i), [3, 7])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_simple_end_single(self):
+        """
+        Check that intersect returns only element, which are present in both
+        non-empty input arrays. One common element is at the end of one array.
+        """
+        a = np.array([2, 3, 6, 7, 9], dtype=self.get_dtype())
+        b = np.array([1, 3, 7, 9, 10], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+
+        self.assertEqual(list(i), [3, 7, 9])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+
+    def test_simple_end_both(self):
+        """
+        Check that intersect returns only element, which are present in both
+        non-empty input arrays. One common element is at the end of both
+        arrays.
+        """
+        a = np.array([2, 3, 6, 7, 9], dtype=self.get_dtype())
+        b = np.array([1, 3, 7, 9], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+
+        self.assertEqual(list(i), [3, 7, 9])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_simple_begining_single(self):
+        """
+        Check that intersect returns only element, which are present in both
+        non-empty input arrays. One common element is at the begining of one array.
+        """
+        a = np.array([2, 3, 6, 7, 8], dtype=self.get_dtype())
+        b = np.array([1, 2, 3, 7, 9, 10], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+
+        self.assertEqual(list(i), [2, 3, 7])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_simple_begining_both(self):
+        """
+        Check that intersect returns only element, which are present in both
+        non-empty input arrays. One common element is at the end of both
+        arrays.
+        """
+        a = np.array([2, 3, 6, 7, 8], dtype=self.get_dtype())
+        b = np.array([2, 3, 7, 9, 10], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+
+        self.assertEqual(list(i), [2, 3, 7])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_empty_intersect(self):
+        """
+        Check that intersect returns an empty array, if the non-empty inputs
+        do not have any elements in common.
+        """
+        a = np.array([1, 3, 5, 10], dtype=self.get_dtype())
+        b = np.array([2, 4, 7, 8, 20], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+
+        self.assertEqual(list(i), [])
+        self.assertEqual(len(i), 0)
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_empty_input_single(self):
+        """
+        Check that intersect returns an empty array, if one of the input arrays
+        is empty.
+        """
+        a = np.array([], dtype=self.get_dtype())
+        b = np.array([2, 4, 7, 8, 20], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+        self.assertEqual(list(i), [])
+        self.assertEqual(len(i), 0)
+        self.assertEqual(i.dtype, self.get_dtype())
+
+        i = snp.intersect(b, a)
+        self.assertEqual(list(i), [])
+        self.assertEqual(len(i), 0)
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_empty_input_both(self):
+        """
+        Check that intersect returns an empty array, both  input arrays are
+        empty.
+        """
+        a = np.array([], dtype=self.get_dtype())
+        b = np.array([], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+        self.assertEqual(list(i), [])
+        self.assertEqual(len(i), 0)
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_contained(self):
+        """
+        Check that intersect returns the common elements, if one array is
+        contained in the other.
+        """
+        a = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=self.get_dtype())
+        b = np.array([4, 5, 7], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+        self.assertEqual(list(i), [4, 5, 7])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+        i = snp.intersect(b, a)
+        self.assertEqual(list(i), [4, 5, 7])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_identical(self):
+        """
+        Check that intersect returns a copy, if the same array is passed in
+        twice.
+        """
+        a = np.array([3, 4, 6, 8], dtype=self.get_dtype())
+
+        i = snp.intersect(a, a)
+        self.assertEqual(list(i), [3, 4, 6, 8])
+        self.assertEqual(list(a), [3, 4, 6, 8])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+        i[0] = 1
+        self.assertEqual(list(a), [3, 4, 6, 8])
+
+    def test_separated(self):
+        """
+        Check that intersect returns an empty array, if all elements are
+        greater than all elements in the other.
+        """
+        a = np.array([1, 2, 3], dtype=self.get_dtype())
+        b = np.array([4, 6, 8], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+        self.assertEqual(list(i), [])
+        self.assertEqual(len(i), 0)
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_duplicates_same(self):
+        """
+        Check that duplicates in the same array are dropped if not present in
+        the other array.
+        """
+        a = np.array([1, 2, 2, 3], dtype=self.get_dtype())
+        b = np.array([1, 6, 8], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+        self.assertEqual(list(i), [1])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+        a = np.array([1, 2, 2, 3], dtype=self.get_dtype())
+        b = np.array([1, 2, 4, 6, 8], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+        self.assertEqual(list(i), [1, 2])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+
+    def test_duplicates_both(self):
+        """
+        Check that duplicates in the same array are kept if they are also
+        duplicated in the other array.
+        """
+        a = np.array([1, 2, 2, 3], dtype=self.get_dtype())
+        b = np.array([2, 2, 4, 6, 8], dtype=self.get_dtype())
+
+        i = snp.intersect(a, b)
+        self.assertEqual(list(i), [2, 2])
+        self.assertEqual(i.dtype, self.get_dtype())
+
+    def test_raise_multi_dim(self):
+        """
+        Check that passing in a multi dimensional array raises an exception.
+        """
+        a = np.zeros((10, 2), dtype=self.get_dtype())
+        b = np.array([2, 3, 5, 6], dtype=self.get_dtype())
+
+        self.assertRaises(ValueError, snp.intersect, a, b)
+        self.assertRaises(ValueError, snp.intersect, b, a)
+        self.assertRaises(ValueError, snp.intersect, a, a)
+        
+    def test_raise_non_array(self):
+        """
+        Check that passing in a non-numpy-array raises an exception.
+        """
+        b = np.array([2, 3, 5, 6], dtype=self.get_dtype())
+
+        self.assertRaises(TypeError, snp.intersect, 3, b)
+        self.assertRaises(TypeError, snp.intersect, b, 2)
+        self.assertRaises(TypeError, snp.intersect, 3, "a")
+        
+
+class IntersectTestCase_Double(IntersectBase, unittest.TestCase):
+    def get_dtype(self):
+        return 'float'
+
+
diff --git a/tests/test_merge.py b/tests/test_merge.py
new file mode 100644
index 0000000000000000000000000000000000000000..83725dabf255fdc6d78e54901797e86fd0fb3406
--- /dev/null
+++ b/tests/test_merge.py
@@ -0,0 +1,156 @@
+
+from abc import ABCMeta, abstractmethod
+import unittest
+import numpy as np
+
+import sortednp as snp
+
+class MergeBase(metaclass=ABCMeta):
+    """
+    Define general test cases for the merge method. Sub-classes need to
+    implement have to overwrite the dtype method.
+    """
+
+    @abstractmethod
+    def get_dtype(self):
+        """
+        Returns the numpy data type, which should be used for all tests.
+        """
+        pass
+    
+
+    def test_simple(self):
+        """
+        Check that merging two non-empty arrays returns the union of the two
+        arrays.
+        """
+        a = np.array([1, 3, 7], dtype=self.get_dtype())
+        b = np.array([2, 5, 6], dtype=self.get_dtype())
+
+        m = snp.merge(a, b)
+        self.assertEqual(list(m), [1, 2, 3, 5, 6, 7])
+        self.assertEqual(m.dtype, self.get_dtype())
+
+    def test_separated(self):
+        """
+        Check that merging two non-empty arrays returns the union of the two
+        arrays if all element in on array are greater than all elements in the
+        other. This tests the copy parts of the implementation.
+        """
+        a = np.array([1, 3, 7], dtype=self.get_dtype())
+        b = np.array([9, 10, 16], dtype=self.get_dtype())
+
+        m = snp.merge(a, b)
+        self.assertEqual(list(m), [1, 3, 7, 9, 10, 16])
+        self.assertEqual(m.dtype, self.get_dtype())
+
+    def test_empty_single(self):
+        """
+        Check that merging two arrays returns a copy of the first one if
+        the other is empty.
+        """
+        a = np.array([1, 3, 7], dtype=self.get_dtype())
+        b = np.array([], dtype=self.get_dtype())
+
+        m = snp.merge(a, b)
+        self.assertEqual(list(m), [1, 3, 7])
+        self.assertEqual(list(a), [1, 3, 7])
+        self.assertEqual(m.dtype, self.get_dtype())
+        m[0] = 0
+        self.assertEqual(list(a), [1, 3, 7])
+
+        m = snp.merge(b, a)
+        self.assertEqual(list(m), [1, 3, 7])
+        self.assertEqual(list(a), [1, 3, 7])
+        self.assertEqual(m.dtype, self.get_dtype())
+        m[0] = 0
+        self.assertEqual(list(a), [1, 3, 7])
+
+
+    def test_empty_both(self):
+        """
+        Check that merging two empty arrays returns an empty array.
+        """
+        a = np.array([], dtype=self.get_dtype())
+        b = np.array([], dtype=self.get_dtype())
+
+        m = snp.merge(a, b)
+        self.assertEqual(list(m), [])
+        self.assertEqual(len(m), 0)
+        self.assertEqual(m.dtype, self.get_dtype())
+
+
+    def test_identical(self):
+        """
+        Check that merging two identical arrays returns each element twice.
+        """
+        a = np.array([1, 3, 7], dtype=self.get_dtype())
+
+        m = snp.merge(a, a)
+        self.assertEqual(list(m), [1, 1, 3, 3, 7, 7])
+        self.assertEqual(m.dtype, self.get_dtype())
+
+
+    def test_duplicates_same(self):
+        """
+        Check that duplications in a single array are passed to the result.
+        """
+        a = np.array([1, 3, 3, 7], dtype=self.get_dtype())
+        b = np.array([2, 5, 6], dtype=self.get_dtype())
+
+        m = snp.merge(a, b)
+        self.assertEqual(list(m), [1, 2, 3, 3, 5, 6, 7])
+        self.assertEqual(m.dtype, self.get_dtype())
+
+    def test_duplicates_other(self):
+        """
+        Check that duplications in the other array are passed to the result.
+        """
+        a = np.array([1, 3, 7], dtype=self.get_dtype())
+        b = np.array([2, 3, 5, 6], dtype=self.get_dtype())
+
+        m = snp.merge(a, b)
+        self.assertEqual(list(m), [1, 2, 3, 3, 5, 6, 7])
+        self.assertEqual(m.dtype, self.get_dtype())
+
+    def test_duplicates_both(self):
+        """
+        Check that duplications in a single and the other array are both passed to
+        the result.
+        """
+        a = np.array([1, 3, 3, 7], dtype=self.get_dtype())
+        b = np.array([2, 3, 5, 6], dtype=self.get_dtype())
+
+        m = snp.merge(a, b)
+        self.assertEqual(list(m), [1, 2, 3, 3, 3, 5, 6, 7])
+        self.assertEqual(m.dtype, self.get_dtype())
+        
+
+    def test_raise_multi_dim(self):
+        """
+        Check that passing in a multi dimensional array raises an exception.
+        """
+        a = np.zeros((10, 2), dtype=self.get_dtype())
+        b = np.array([2, 3, 5, 6], dtype=self.get_dtype())
+
+        self.assertRaises(ValueError, snp.merge, a, b)
+        self.assertRaises(ValueError, snp.merge, b, a)
+        self.assertRaises(ValueError, snp.merge, a, a)
+        
+    def test_raise_non_array(self):
+        """
+        Check that passing in a non-numpy-array raises an exception.
+        """
+        b = np.array([2, 3, 5, 6], dtype=self.get_dtype())
+
+        self.assertRaises(TypeError, snp.merge, 3, b)
+        self.assertRaises(TypeError, snp.merge, b, 2)
+        self.assertRaises(TypeError, snp.merge, 3, "a")
+        
+
+class MergeTestCase_Double(MergeBase, unittest.TestCase):
+    def get_dtype(self):
+        return 'float'
+
+
+