diff --git a/Core/include/Acts/Utilities/Helpers.hpp b/Core/include/Acts/Utilities/Helpers.hpp
index e37fc8b032492bea69f473a97422a87625e97223..5bc4df0cae94e6cc1e30f5da4678bfd494b37419 100644
--- a/Core/include/Acts/Utilities/Helpers.hpp
+++ b/Core/include/Acts/Utilities/Helpers.hpp
@@ -14,6 +14,7 @@
 
 // libc/STL include(s)
 #include <cmath>
+#include <cstdlib>
 #include <iomanip>
 #include <iostream>
 #include <memory>
@@ -65,50 +66,133 @@ namespace VectorHelpers {
 
   }  // namespace detail
 
-  // default call on Eigen types, calculate radius
+  /// Calculate phi (transverse plane angle) from compatible Eigen types
+  /// @tparam Derived Eigen derived concrete type
+  /// @param v Any vector like Eigen type, static or dynamic
+  /// @note Will static assert that the number of rows of @p v is at least 2, or
+  /// in case of dynamic size, will abort execution if that is not the case.
+  /// @return The value of the angle in the transverse plane.
   template <typename Derived>
   double
-  phi(const Eigen::MatrixBase<Derived>& v)
+  phi(const Eigen::MatrixBase<Derived>& v) noexcept
   {
-    if (v.rows() < 2) {
-      return 0.;
+    constexpr int rows = Eigen::MatrixBase<Derived>::RowsAtCompileTime;
+    if
+      constexpr(rows != -1)
+      {
+        // static size, do compile time check
+        static_assert(rows >= 2,
+                      "Phi function not valid for vectors not at least 2D");
+      }
+    else {
+      // dynamic size
+      if (v.rows() < 2) {
+        std::cerr << "Phi function not valid for vectors not at least 2D"
+                  << std::endl;
+        std::abort();
+      }
     }
+
     return std::atan2(v[1], v[0]);
   }
 
-  // if called-upon type has phi method, call that
+  /// Calculate phi (transverse plane angle) from anything implementing a method
+  /// like `phi()` returing anything convertible to `double`.
+  /// @tparam T anything that has a phi method
+  /// @param v Any type that implements a phi method
+  /// @return The phi value
   template <typename T,
             std::enable_if_t<detail::has_phi_method<T>::value, int> = 0>
   double
-  phi(const T& v)
+  phi(const T& v) noexcept
   {
     return v.phi();
   }
 
+  /// Calculate radius in the transverse (xy) plane of a vector
+  /// @tparam Derived Eigen derived concrete type
+  /// @param v Any vector like Eigen type, static or dynamic
+  /// @note Will static assert that the number of rows of @p v is at least 2, or
+  /// in case of dynamic size, will abort execution if that is not the case.
+  /// @return The transverse radius value.
   template <typename Derived>
   double
-  perp(const Eigen::MatrixBase<Derived>& v)
+  perp(const Eigen::MatrixBase<Derived>& v) noexcept
   {
-    if (v.rows() < 2) {
-      return 0.;
+    constexpr int rows = Eigen::MatrixBase<Derived>::RowsAtCompileTime;
+    if
+      constexpr(rows != -1)
+      {
+        // static size, do compile time check
+        static_assert(rows >= 2,
+                      "Perp function not valid for vectors not at least 2D");
+      }
+    else {
+      // dynamic size
+      if (v.rows() < 2) {
+        std::cerr << "Perp function not valid for vectors not at least 2D"
+                  << std::endl;
+        std::abort();
+      }
     }
     return std::sqrt(v[0] * v[0] + v[1] * v[1]);
   }
 
+  /// Calculate the theta angle (longitudinal w.r.t. z axis) of a vector
+  /// @tparam Derived Eigen derived concrete type
+  /// @param v Any vector like Eigen type, static or dynamic
+  /// @note Will static assert that the number of rows of @p v is at least 3, or
+  /// in case of dynamic size, will abort execution if that is not the case.
+  /// @return The theta value
   template <typename Derived>
   double
-  theta(const Eigen::MatrixBase<Derived>& v)
+  theta(const Eigen::MatrixBase<Derived>& v) noexcept
   {
-    if (v.rows() < 3) {
-      return 0.;
+    constexpr int rows = Eigen::MatrixBase<Derived>::RowsAtCompileTime;
+    if
+      constexpr(rows != -1)
+      {
+        // static size, do compile time check
+        static_assert(rows >= 3,
+                      "Theta function not valid for non-3D vectors.");
+      }
+    else {
+      // dynamic size
+      if (v.rows() < 3) {
+        std::cerr << "Theta function not valid for non-3D vectors."
+                  << std::endl;
+        std::abort();
+      }
     }
+
     return std::atan2(std::sqrt(v[0] * v[0] + v[1] * v[1]), v[2]);
   }
 
+  /// Calculate the pseudorapidity for a vector.
+  /// @tparam Derived Eigen derived concrete type
+  /// @param v Any vector like Eigen type, static or dynamic
+  /// @note Will static assert that the number of rows of @p v is at least 3, or
+  /// in case of dynamic size, will abort execution if that is not the case.
+  /// @return The pseudorapidity value
   template <typename Derived>
   double
-  eta(const Eigen::MatrixBase<Derived>& v)
+  eta(const Eigen::MatrixBase<Derived>& v) noexcept
   {
+    constexpr int rows = Eigen::MatrixBase<Derived>::RowsAtCompileTime;
+    if
+      constexpr(rows != -1)
+      {
+        // static size, do compile time check
+        static_assert(rows >= 3, "Eta function not valid for non-3D vectors.");
+      }
+    else {
+      // dynamic size
+      if (v.rows() < 3) {
+        std::cerr << "Eta function not valid for non-3D vectors." << std::endl;
+        std::abort();
+      }
+    }
+
     return std::atanh(v[2] / v.norm());
   }
 
@@ -142,6 +226,11 @@ namespace detail {
   }
 }
 
+/// Print out a matrix in a structured way.
+/// @param matrix The matrix to print
+/// @param precision Numeric output precision
+/// @param offset Offset in front of matrix lines
+/// @return The printed string
 inline std::string
 toString(const ActsMatrixXd& matrix,
          int                 precision = 4,
@@ -185,6 +274,10 @@ toString(const ActsMatrixXd& matrix,
   return sout.str();
 }
 
+/// Print out a translation in a structured way.
+/// @param matrix The translation to print
+/// @param precision Numeric output precision
+/// @return The printed string
 inline std::string
 toString(const Acts::Translation3D& translation, int precision = 4)
 {
@@ -195,6 +288,11 @@ toString(const Acts::Translation3D& translation, int precision = 4)
   return toString(trans, precision);
 }
 
+/// Print out a transform in a structured way.
+/// @param matrix The transform to print
+/// @param precision Numeric output precision
+/// @param offset Offset in front of matrix lines
+/// @return The printed string
 inline std::string
 toString(const Acts::Transform3D& transform,
          int                      precision = 4,
@@ -209,6 +307,11 @@ toString(const Acts::Transform3D& transform,
   return sout.str();
 }
 
+/// Helper function to unpack a vector of @c shared_ptr into a vector of raw
+/// pointers
+/// @tparam T the stored type
+/// @param items The vector of @c shared_ptr
+/// @return The unpacked vector
 template <typename T>
 std::vector<T*>
 unpack_shared_vector(const std::vector<std::shared_ptr<T>>& items)
@@ -221,6 +324,11 @@ unpack_shared_vector(const std::vector<std::shared_ptr<T>>& items)
   return rawPtrs;
 }
 
+/// Helper function to unpack a vector of @c shared_ptr into a vector of raw
+/// pointers (const version)
+/// @tparam T the stored type
+/// @param items The vector of @c shared_ptr
+/// @return The unpacked vector
 template <typename T>
 std::vector<const T*>
 unpack_shared_vector(const std::vector<std::shared_ptr<const T>>& items)
diff --git a/Tests/Core/Utilities/CMakeLists.txt b/Tests/Core/Utilities/CMakeLists.txt
index bdf9024a8b7f43c23683f698a22c736763ef86d8..a140dd4098525dc2fa7668a3da3e48585c066091 100644
--- a/Tests/Core/Utilities/CMakeLists.txt
+++ b/Tests/Core/Utilities/CMakeLists.txt
@@ -79,4 +79,8 @@ add_test (NAME VisualizationTests COMMAND VisualizationTests)
 add_executable (MaterialMapUtilsTests MaterialMapUtilsTests.cpp)
 target_link_libraries (MaterialMapUtilsTests PRIVATE ActsCore ActsTestsCommonHelpers)
 add_test (NAME MaterialMapUtilsTest COMMAND MaterialMapUtilsTests)
-acts_add_test_to_cdash_project (PROJECT ACore TEST MaterialMapUtilsTest TARGETS MaterialMapUtilsTests)
\ No newline at end of file
+acts_add_test_to_cdash_project (PROJECT ACore TEST MaterialMapUtilsTest TARGETS MaterialMapUtilsTests)
+
+add_executable (HelpersTests HelpersTests.cpp)
+target_link_libraries (HelpersTests PRIVATE ActsCore ActsTestsCommonHelpers ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
+add_test (NAME HelpersTests COMMAND HelpersTests)
diff --git a/Tests/Core/Utilities/HelpersTests.cpp b/Tests/Core/Utilities/HelpersTests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0ae407b4240a667e57aef76ec53ca8f8eefc9ac
--- /dev/null
+++ b/Tests/Core/Utilities/HelpersTests.cpp
@@ -0,0 +1,157 @@
+// This file is part of the Acts project.
+//
+// Copyright (C) 2019 Acts project team
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#define BOOST_TEST_MODULE Helpers Tests
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+#include "Acts/Tests/CommonHelpers/FloatComparisons.hpp"
+#include "Acts/Utilities/Helpers.hpp"
+
+using namespace Acts::VectorHelpers;
+
+namespace Acts {
+namespace Test {
+
+  BOOST_AUTO_TEST_SUITE(Utilities)
+
+  struct MyStruct
+  {
+    double
+    phi() const
+    {
+      return 42;
+    }
+  };
+
+  BOOST_AUTO_TEST_CASE(phi_helper_test)
+  {
+    Vector3D v(0, 1, 0);
+    CHECK_CLOSE_ABS(phi(v), M_PI / 2., 1e-9);
+
+    // should work with dynamic types as well
+    ActsVectorXd v2{3};
+    v2 << 0, 1, 0;
+    CHECK_CLOSE_ABS(phi(v2), M_PI / 2., 1e-9);
+
+    MyStruct s;
+    BOOST_CHECK_EQUAL(phi(s), 42);
+  }
+
+  BOOST_AUTO_TEST_CASE(perp_helper_test)
+  {
+    Vector3D v(1, 2, 3);
+    CHECK_CLOSE_ABS(perp(v), std::sqrt(1 + 2 * 2), 1e-9);
+
+    // should work with dynamic types as well
+    ActsVectorXd v2{3};
+    v2 << 1, 2, 3;
+    CHECK_CLOSE_ABS(perp(v2), std::sqrt(1 + 2 * 2), 1e-9);
+  }
+
+  BOOST_AUTO_TEST_CASE(theta_eta_test_helper)
+  {
+    Vector3D v(1, 2, 3);
+    CHECK_CLOSE_ABS(theta(v), 0.640522, 1e-5);
+    CHECK_CLOSE_ABS(eta(v), 1.10359, 1e-5);
+
+    // should work with dynamic types as well
+    ActsVectorXd v2{3};
+    v2 << 1, 2, 3;
+    CHECK_CLOSE_ABS(theta(v2), 0.640522, 1e-5);
+    CHECK_CLOSE_ABS(eta(v2), 1.10359, 1e-5);
+  }
+
+  BOOST_AUTO_TEST_CASE(cross_test_helper)
+  {
+    {
+      Vector3D v(1, 2, 3);
+      ActsMatrixD<3, 3> mat;
+      mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+
+      ActsMatrixD<3, 3> act = cross(mat, v);
+      ActsMatrixD<3, 3> exp;
+      exp << -2, -1, 0, 4, 2, 0, -2, -1, 0;
+
+      CHECK_CLOSE_ABS(act, exp, 1e-9);
+    }
+
+    // should work with dynamic types as well
+    {
+      ActsVectorXd v{3};
+      v << 1, 2, 3;
+      ActsMatrixXd mat{3, 3};
+      mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+
+      ActsMatrixXd act = cross(mat, v);
+      ActsMatrixXd exp{3, 3};
+      exp << -2, -1, 0, 4, 2, 0, -2, -1, 0;
+
+      BOOST_CHECK(act.isApprox(exp, 1e-9));
+    }
+  }
+
+  BOOST_AUTO_TEST_CASE(toString_test_helper)
+  {
+    ActsMatrixD<3, 3> mat;
+    mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
+    std::string out;
+    out = toString(mat);
+    BOOST_CHECK(out.size() > 0);
+
+    Translation3D trl{Vector3D{1, 2, 3}};
+    out = toString(trl);
+    BOOST_CHECK(out.size() > 0);
+
+    Transform3D trf;
+    trf = trl;
+    out = toString(trf);
+    BOOST_CHECK(out.size() > 0);
+  }
+
+  BOOST_AUTO_TEST_CASE(shared_vector_helper_test)
+  {
+    {
+      std::vector<std::shared_ptr<int>> vec;
+      vec = {std::make_shared<int>(5),
+             std::make_shared<int>(9),
+             std::make_shared<int>(26),
+             std::make_shared<int>(18473)};
+
+      std::vector<int*> unpacked = unpack_shared_vector(vec);
+
+      std::vector<int*> exp = {
+          vec[0].get(), vec[1].get(), vec[2].get(), vec[3].get(),
+      };
+
+      BOOST_CHECK_EQUAL_COLLECTIONS(
+          unpacked.begin(), unpacked.end(), exp.begin(), exp.end());
+    }
+
+    // same for const
+    {
+      std::vector<std::shared_ptr<const int>> vec;
+      vec = {std::make_shared<const int>(5),
+             std::make_shared<const int>(9),
+             std::make_shared<const int>(26),
+             std::make_shared<const int>(18473)};
+
+      std::vector<const int*> unpacked = unpack_shared_vector(vec);
+
+      std::vector<const int*> exp = {
+          vec[0].get(), vec[1].get(), vec[2].get(), vec[3].get(),
+      };
+
+      BOOST_CHECK_EQUAL_COLLECTIONS(
+          unpacked.begin(), unpacked.end(), exp.begin(), exp.end());
+    }
+  }
+
+  BOOST_AUTO_TEST_SUITE_END()
+}
+}