diff --git a/.gitmodules b/.gitmodules
index b03f7351c6e6a4eaaa5521f6c7a44deded20a9a2..eca2363e385ce7bd01c2e6f4d4b4c32af9b3fe94 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,6 @@
 [submodule "ext/nanogui"]
 	path = ext/nanogui
 	url = https://github.com/wjakob/nanogui.git
-[submodule "SDK/C++/public/ext/pybind11"]
-	path = SDK/C++/public/ext/pybind11
+[submodule "SDK/CPP/public/ext/pybind11"]
+	path = SDK/CPP/public/ext/pybind11
 	url = https://github.com/pybind/pybind11.git
diff --git a/SDK/CPP/public/CMakeLists.txt b/SDK/CPP/public/CMakeLists.txt
index a0eb7eaf58262395b4232cba3a0421cb144ccfca..e31bbdf7fabc7f07d8e3d9b0498e6748851a05e5 100644
--- a/SDK/CPP/public/CMakeLists.txt
+++ b/SDK/CPP/public/CMakeLists.txt
@@ -6,10 +6,15 @@ include(GNUInstallDirs)
 
 option(WITH_OPENCV "Build with OpenCV wrapper" ON)
 option(WITH_PYTHON "Build Python module" OFF)
+option(WITH_TESTS "Enable unit tests" ON)
 
 find_package( Eigen3 REQUIRED NO_MODULE )
 find_package( Threads REQUIRED )
 
+if (WITH_TESTS)
+	enable_testing()
+endif()
+
 if (WITH_OPENCV)
 	find_package( OpenCV REQUIRED )
 endif()
diff --git a/SDK/CPP/public/ext/pybind11 b/SDK/CPP/public/ext/pybind11
new file mode 160000
index 0000000000000000000000000000000000000000..06b673a0daef1db4f921a19676a51abec6fb13e8
--- /dev/null
+++ b/SDK/CPP/public/ext/pybind11
@@ -0,0 +1 @@
+Subproject commit 06b673a0daef1db4f921a19676a51abec6fb13e8
diff --git a/SDK/CPP/public/python/CMakeLists.txt b/SDK/CPP/public/python/CMakeLists.txt
index 40bd39c8b388c667af935563da800a62910f0deb..473b0626c2190b4602b485b855fa3447ca3839bc 100644
--- a/SDK/CPP/public/python/CMakeLists.txt
+++ b/SDK/CPP/public/python/CMakeLists.txt
@@ -32,13 +32,6 @@ target_include_directories(voltu_sdk_py PRIVATE .)
 target_link_libraries(voltu_sdk_py PUBLIC voltu_sdk)
 set_target_properties(voltu_sdk_py PROPERTIES OUTPUT_NAME voltu)
 
-enable_testing()
-find_package(Python3 COMPONENTS Interpreter)
-
-function(add_python_test TEST_NAME TEST_SCRIPT)
-    add_test(NAME ${TEST_NAME}
-        COMMAND Python3::Interpreter -m unittest ${TEST_SCRIPT}
-        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
-endfunction()
-
-add_python_test(test_load tests/test_load.py)
+if (WITH_TESTS)
+    add_subdirectory(tests)
+endif()
diff --git a/SDK/CPP/public/python/module.cpp b/SDK/CPP/public/python/module.cpp
index 5ba4e9e2a48f24cbe34353796bf23728f2f93656..8564a388ef67f2b2adbdc929ae3c2e5e579700c9 100644
--- a/SDK/CPP/public/python/module.cpp
+++ b/SDK/CPP/public/python/module.cpp
@@ -1,6 +1,7 @@
 
 #include "module.hpp"
 
+#include <voltu/voltu.hpp>
 #include <voltu/initialise.hpp>
 #include <voltu/types/errors.hpp>
 
@@ -15,6 +16,7 @@ void py_exceptions(pybind11::module& m) {
 }
 
 PYBIND11_MODULE(voltu, m) {
+	m.attr("version") = py::make_tuple(VOLTU_VERSION_MAJOR, VOLTU_VERSION_MINOR, VOLTU_VERSION_PATCH);
 	py_exceptions(m);
 	py_automatic_bindings(m);
 }
diff --git a/SDK/CPP/public/python/tests/CMakeLists.txt b/SDK/CPP/public/python/tests/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..dfdc1b01bcef651a7c06678dad9f8cba415691b3
--- /dev/null
+++ b/SDK/CPP/public/python/tests/CMakeLists.txt
@@ -0,0 +1,12 @@
+find_package(Python3 COMPONENTS Interpreter)
+
+function(add_python_test TEST_NAME TEST_SCRIPT)
+    add_test(NAME ${TEST_NAME}
+        COMMAND Python3::Interpreter -B -m unittest ${TEST_SCRIPT}
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+    # binary module directory to PYTHONPATH
+    set_tests_properties(${TEST_NAME} PROPERTIES
+        ENVIRONMENT PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}/..)
+endfunction()
+
+add_python_test(TestLoad test_load.py)
diff --git a/SDK/CPP/public/python/tests/test_load.py b/SDK/CPP/public/python/tests/test_load.py
index 8e5131d4d4299af3ac116f3585de9403b6ee2f9d..da800f67563627d12ee3809cef2f641dd01ee9a7 100644
--- a/SDK/CPP/public/python/tests/test_load.py
+++ b/SDK/CPP/public/python/tests/test_load.py
@@ -1,12 +1,17 @@
 import unittest
+import os
+import voltu
 
 class LoadLibrary(unittest.TestCase):
 
     def test_get_instance(self):
-        import voltu
         self.assertIsNotNone(voltu.instance())
-        # second call to instance() returns None
-        #self.assertIsNotNone(voltu.instance())
+        # second call to instance() returns None; should
+        # return same instance instead?
+        # self.assertIsNotNone(voltu.instance())
+
+    def test_version(self):
+        major, minor, patch = voltu.version
 
 if __name__ == '__main__':
     unittest.main()