diff --git a/pkg/cn-cbor/Makefile b/pkg/cn-cbor/Makefile
index 20b61f4fa5882ddadf8d9419d36f867f72a73079..094c57bec97457f88c99e67af08dcf3a185043c7 100644
--- a/pkg/cn-cbor/Makefile
+++ b/pkg/cn-cbor/Makefile
@@ -6,7 +6,6 @@ PKG_LICENSE=MIT
 .PHONY: all
 
 all: git-download
-	@cp Makefile.cn-cbor $(PKG_BUILDDIR)/src/Makefile
-	"$(MAKE)" -C $(PKG_BUILDDIR)/src
+	"$(MAKE)" -C $(PKG_BUILDDIR)/src -f $(CURDIR)/Makefile.cn-cbor
 
 include $(RIOTBASE)/pkg/pkg.mk
diff --git a/tests/pkg_cn-cbor/Makefile b/tests/pkg_cn-cbor/Makefile
deleted file mode 100644
index ca46a198a0e2aaaa488175b6839a7644c5c25093..0000000000000000000000000000000000000000
--- a/tests/pkg_cn-cbor/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-APPLICATION = pkg_cn-cbor
-include ../Makefile.tests_common
-
-USEPKG += cn-cbor
-USEMODULE += posix
-
-include $(RIOTBASE)/Makefile.include
-
-test:
-	tests/01-run.py
diff --git a/tests/pkg_cn-cbor/main.c b/tests/pkg_cn-cbor/main.c
deleted file mode 100644
index b505160e582f8ce0ea9c169cfdafd94ae87e7409..0000000000000000000000000000000000000000
--- a/tests/pkg_cn-cbor/main.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-/**
- * @ingroup     tests
- * @{
- *
- * @file
- * @brief       cn-cbor test application
- *
- * @author      Kaspar Schleiser <kaspar@schleiser.de>
- *
- * @}
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "cn-cbor/cn-cbor.h"
-
-#define CBOR_TEST   { 0x17 }    /* 23 */
-
-int main(void)
-{
-    const char cbor[] = CBOR_TEST;
-
-    cn_cbor *c = cn_cbor_decode((const uint8_t *)cbor, strlen(cbor), NULL);
-
-    if (c && (c->v.sint == 23)) {
-        puts("[SUCCESS]");
-    }
-    else {
-        puts("[FAIL]");
-    }
-
-    return 0;
-}
diff --git a/tests/pkg_cn-cbor/tests/01-run.py b/tests/pkg_cn-cbor/tests/01-run.py
deleted file mode 100755
index a50a5fce03dbbc0b4381dc12071d4ba8aa86cc0e..0000000000000000000000000000000000000000
--- a/tests/pkg_cn-cbor/tests/01-run.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python3
-
-import os
-import sys
-
-sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
-import testrunner
-
-
-def testfunc(child):
-    child.expect('[SUCCESS]')
-
-if __name__ == "__main__":
-    sys.exit(testrunner.run(testfunc))
diff --git a/tests/unittests/tests-cn_cbor/Makefile b/tests/unittests/tests-cn_cbor/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..a7ee51ee2d5badbfebcbc33160399ea59788baa1
--- /dev/null
+++ b/tests/unittests/tests-cn_cbor/Makefile
@@ -0,0 +1,8 @@
+include $(RIOTBASE)/Makefile.base
+
+# Tests will fail on platforms <64 bit if not set.
+# Workaround for missing overflow detection in cn-cbor.
+CFLAGS += -DCBOR_NO_LL
+
+# Skips test cases for floating point data types.
+# CFLAGS += -DCBOR_NO_FLOAT
diff --git a/tests/unittests/tests-cn_cbor/Makefile.include b/tests/unittests/tests-cn_cbor/Makefile.include
new file mode 100644
index 0000000000000000000000000000000000000000..099fc733819d234d2b4c1b7d25b9af15b7e7b040
--- /dev/null
+++ b/tests/unittests/tests-cn_cbor/Makefile.include
@@ -0,0 +1 @@
+USEPKG += cn-cbor
diff --git a/tests/unittests/tests-cn_cbor/tests-cn_cbor.c b/tests/unittests/tests-cn_cbor/tests-cn_cbor.c
new file mode 100644
index 0000000000000000000000000000000000000000..e55246349c099a3864949c819fee5abb45d701a7
--- /dev/null
+++ b/tests/unittests/tests-cn_cbor/tests-cn_cbor.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) Lorenz Hüther, Mathias Detmers
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+ /**
+  * @ingroup    tests
+  * @{
+  *
+  * @file
+  * @brief      Unit tests for pkg cn-cbor.
+  *
+  * @author     Lorenz Hüther <lorenz.huether@uni-bremen.de>
+  * @author     Mathias Detmers <detmat@uni-bremen.de
+  */
+
+#define EBUF_SIZE 32
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cn-cbor/cn-cbor.h"
+#include "embUnit.h"
+
+typedef struct buffer {
+    size_t size;
+    unsigned char *pntr;
+} buffer_t;
+
+typedef struct {
+    char *hex;
+    cn_cbor_error err;
+} cbor_failure;
+
+static cn_cbor *cbor;
+static buffer_t pbuf;
+static size_t test, offs;
+static unsigned char ebuf[EBUF_SIZE];
+static cn_cbor_errback errb;
+
+static void setup_cn_cbor(void)
+{
+    cbor = NULL;
+    test = 0;
+    offs = 0;
+    memset(ebuf, '\0', EBUF_SIZE);
+}
+
+static void teardown_cn_cbor(void)
+{
+        free(pbuf.pntr);
+        cn_cbor_free(cbor);
+}
+
+static bool parse_hex(char *inpt)
+{
+    int strl = strlen(inpt);
+    size_t offs;
+
+    if (strl % 2 != 0) {
+        pbuf.size = -1;
+        pbuf.pntr = NULL;
+        return false;
+    }
+
+    pbuf.size = strl / 2;
+    pbuf.pntr = malloc(pbuf.size);
+
+    for (offs = 0; offs < pbuf.size; offs++) {
+        sscanf(inpt + (2 * offs), "%02hhx", &pbuf.pntr[offs]);
+    }
+
+    return true;
+}
+
+static void test_parse(void)
+{
+    char *tests[] = {
+        "00",                       // 0
+        "01",                       // 1
+        "17",                       // 23
+        "1818",                     // 24
+        "190100",                   // 256
+        "1a00010000",               // 65536
+#ifndef CBOR_NO_LL
+        "1b0000000100000000",       // 4294967296
+#endif /* CBOR_NO_LL */
+
+        "20",                       // -1
+        "37",                       // -24
+        "3818",                     // -25
+        "390100",                   // -257
+        "3a00010000",               // -65537
+#ifndef CBOR_NO_LL
+        "3b0000000100000000",       // -4294967297
+#endif /* CBOR_LL */
+        "4161",                     // h"a"
+        "6161",                     // "a"
+        "80",                       // []
+        "8100",                     // [0]
+        "820102",                   // [1,2]
+        "818100",                   // [[0]]
+        "a1616100",                 // {"a":0}
+        "d8184100",                 // tag
+        "f4",                       // false
+        "f5",                       // true
+        "f6",                       // null
+        "f7",                       // undefined
+        "f8ff",                     // simple(255)
+
+#ifndef CBOR_NO_FLOAT
+        "f93c00",                   // 1.0
+        "f9bc00",                   // -1.0
+        "f903ff",                   // 6.097555160522461e-05
+        "f90400",                   // 6.103515625e-05
+        "f907ff",                   // 0.00012201070785522461
+        "f90800",                   // 0.0001220703125
+        "fa47800000",               // 65536.0
+        "fb3ff199999999999a",       // 1.1
+        "f97e00",                   // NaN
+#endif /* CBOR_NO_FLOAT */
+
+        "5f42010243030405ff",       // (_ h'0102', h'030405')
+        "7f61616161ff",             // (_ "a", "a")
+        "9fff",                     // [_ ]
+        "9f9f9fffffff",             // [_ [_ [_ ]]]
+        "9f009f00ff00ff",           // [_ 0, [_ 0], 0]
+        "bf61610161629f0203ffff",   // {_ "a": 1, "b": [_ 2, 3]}
+    };
+
+    for (test = 0; test < sizeof(tests) / sizeof(char*); test++) {
+        TEST_ASSERT(parse_hex(tests[test]));
+        errb.err = CN_CBOR_NO_ERROR;
+
+        cbor = cn_cbor_decode(pbuf.pntr, pbuf.size, &errb);
+        TEST_ASSERT_EQUAL_INT(errb.err, CN_CBOR_NO_ERROR);
+        TEST_ASSERT_NOT_NULL(cbor);
+
+        cn_cbor_encoder_write(ebuf, 0, sizeof(ebuf), cbor);
+        for (offs = 0; offs < pbuf.size; offs++) {
+            TEST_ASSERT_EQUAL_INT(pbuf.pntr[offs], ebuf[offs]);
+        }
+    }
+}
+
+static void test_errors(void)
+{
+    cbor_failure tests[] = {
+        {"81", CN_CBOR_ERR_OUT_OF_DATA},
+        {"0000", CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED},
+        {"bf00ff", CN_CBOR_ERR_ODD_SIZE_INDEF_MAP},
+        {"ff", CN_CBOR_ERR_BREAK_OUTSIDE_INDEF},
+        {"1f", CN_CBOR_ERR_MT_UNDEF_FOR_INDEF},
+        {"1c", CN_CBOR_ERR_RESERVED_AI},
+        {"7f4100", CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING},
+    };
+
+    cn_cbor inv = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL};
+
+    TEST_ASSERT_EQUAL_INT(-1, cn_cbor_encoder_write(ebuf, 0, sizeof(ebuf),
+            &inv));
+
+    for (offs = 0; offs < sizeof(tests) / sizeof(cbor_failure); offs++) {
+        TEST_ASSERT(parse_hex(tests[offs].hex));
+
+        cbor = cn_cbor_decode(pbuf.pntr, pbuf.size, &errb);
+        TEST_ASSERT_NULL(cbor);
+        TEST_ASSERT_EQUAL_INT(errb.err, tests[offs].err);
+    }
+}
+
+TestRef test_cn_cbor(void)
+{
+    EMB_UNIT_TESTFIXTURES(fixtures) {
+        new_TestFixture(test_parse),
+        new_TestFixture(test_errors)
+    };
+
+    EMB_UNIT_TESTCALLER(tests_cn_cbor, setup_cn_cbor, teardown_cn_cbor, fixtures);
+    return (TestRef) & tests_cn_cbor;
+}
+
+void tests_cn_cbor(void)
+{
+    TESTS_RUN(test_cn_cbor());
+}