diff --git a/tests/cb_mux/Makefile b/tests/cb_mux/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..85812a0d9df5bab77d7e723b10eca1bd02ece86a
--- /dev/null
+++ b/tests/cb_mux/Makefile
@@ -0,0 +1,10 @@
+include ../Makefile.tests_common
+
+USEMODULE += cb_mux
+
+TEST_ON_CI_WHITELIST += all
+
+include $(RIOTBASE)/Makefile.include
+
+test:
+	./tests/01-run.py
diff --git a/tests/cb_mux/main.c b/tests/cb_mux/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..872834ed7b5710fd143f963d76bfff6ea1fcd992
--- /dev/null
+++ b/tests/cb_mux/main.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 Acutam Automation, LLC
+ *
+ * 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       cb_mux test application
+ *
+ * @author      Matthew Blue <matthew.blue.neuro@gmail.com>
+ * @}
+ */
+
+#include <stdio.h>
+
+#include "cb_mux.h"
+
+/* Head of cb_mux list */
+cb_mux_t *cb_mux_head;
+
+/* Flags for mux_iter */
+enum {
+    ITER_TEST = 1
+};
+
+/* Function to iterate over cb_mux list */
+void mux_iter(cb_mux_t *entry, void *arg)
+{
+    (void)arg;
+
+    entry->info = (void *)((uintptr_t)entry->info | (1 << ITER_TEST));
+}
+
+/* Test callback */
+void cb(void *arg)
+{
+    printf("Callback %u executed\n", (uint8_t)(uintptr_t)arg);
+}
+
+int main(void)
+{
+    cb_mux_t entries[5];
+    cb_mux_cbid_t num;
+    cb_mux_t *entry;
+
+    puts("cb_mux test routine");
+
+    for (num = 0; num < 5; num++) {
+        entries[num].cb = cb;
+        entries[num].arg = (void *)num;
+        entries[num].cbid = num;
+    }
+
+    puts("Test list addition, retrieval, execution of 5 CBs");
+
+    for (num = 0; num < 5; num++) {
+        cb_mux_add(&cb_mux_head, &(entries[num]));
+    }
+
+    for (num = 0; num < 5; num++) {
+        entry = cb_mux_find_cbid(cb_mux_head, num);
+
+        if (entry->cb == NULL) {
+            puts("[FAILED] Unexpected NULL pointer");
+            return 1;
+        }
+
+        entry->cb(entry->arg);
+    }
+
+    puts("Test list deletion of CB 0, 2, 4, execution of 1, 3");
+
+    cb_mux_del(&cb_mux_head, &(entries[0]));
+    cb_mux_del(&cb_mux_head, &(entries[2]));
+    cb_mux_del(&cb_mux_head, &(entries[4]));
+
+    for (num = 0; num < 5; num++) {
+        entry = cb_mux_find_cbid(cb_mux_head, num);
+
+        if (entry == NULL) {
+            continue;
+        }
+
+        entry->cb(entry->arg);
+    }
+
+    puts("Test execution of CB with lowest ID (1)");
+
+    entry = cb_mux_find_low(cb_mux_head);
+    if (entry->cb == NULL) {
+        puts("[FAILED] Unexpected NULL pointer");
+        return 1;
+    }
+    entry->cb(entry->arg);
+
+    puts("Test execution of CB with highest ID (3)");
+
+    entry = cb_mux_find_high(cb_mux_head);
+    if (entry->cb == NULL) {
+        puts("[FAILED] Unexpected NULL pointer");
+        return 1;
+    }
+    entry->cb(entry->arg);
+
+    puts("Re-adding list entries (0, 2, 4) by finding next free ID");
+
+    num = cb_mux_find_free_id(cb_mux_head);
+    while (num < 5) {
+        cb_mux_add(&cb_mux_head, &(entries[num]));
+
+        printf("Added entry %i\n", num);
+
+        num = cb_mux_find_free_id(cb_mux_head);
+    }
+
+    puts("Test iteration of a function over list");
+
+    cb_mux_iter(cb_mux_head, mux_iter, NULL);
+
+    for (num = 0; num < 5; num++) {
+        if ((uintptr_t)entries[num].info & (1 << ITER_TEST)) {
+            printf("Entry %i was updated correctly\n", num);
+        }
+    }
+
+    puts("Tests complete!");
+
+    return 0;
+}
diff --git a/tests/cb_mux/tests/01-run.py b/tests/cb_mux/tests/01-run.py
new file mode 100755
index 0000000000000000000000000000000000000000..d501e26601605e988f398fbe9d6b3f7bacb5e5e6
--- /dev/null
+++ b/tests/cb_mux/tests/01-run.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2018 Acutam Automation, LLC
+#
+# 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.
+
+import os
+import sys
+
+
+def testfunc(child):
+    child.expect_exact("cb_mux test routine")
+    child.expect_exact("Test list addition, retrieval, execution of 5 CBs")
+    child.expect_exact("Callback 0 executed")
+    child.expect_exact("Callback 1 executed")
+    child.expect_exact("Callback 2 executed")
+    child.expect_exact("Callback 3 executed")
+    child.expect_exact("Callback 4 executed")
+    child.expect_exact("Test list deletion of CB 0, 2, 4, execution of 1, 3")
+    child.expect_exact("Callback 1 executed")
+    child.expect_exact("Callback 3 executed")
+    child.expect_exact("Test execution of CB with lowest ID (1)")
+    child.expect_exact("Callback 1 executed")
+    child.expect_exact("Test execution of CB with highest ID (3)")
+    child.expect_exact("Callback 3 executed")
+    child.expect_exact("Re-adding list entries (0, 2, 4) by finding next free ID")
+    child.expect_exact("Added entry 0")
+    child.expect_exact("Added entry 2")
+    child.expect_exact("Added entry 4")
+    child.expect_exact("Test iteration of a function over list")
+    child.expect_exact("Entry 0 was updated correctly")
+    child.expect_exact("Entry 1 was updated correctly")
+    child.expect_exact("Entry 2 was updated correctly")
+    child.expect_exact("Entry 3 was updated correctly")
+    child.expect_exact("Entry 4 was updated correctly")
+    child.expect_exact("Tests complete!")
+
+
+if __name__ == "__main__":
+    sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
+    from testrunner import run
+    sys.exit(run(testfunc))