diff --git a/tests/include/aocTests/TestContext.hpp b/tests/include/aocTests/TestContext.hpp
index 23f8aff..9f86ca9 100644
--- a/tests/include/aocTests/TestContext.hpp
+++ b/tests/include/aocTests/TestContext.hpp
@@ -19,23 +19,57 @@
 #include <string>
 #include <vector>
 
+#include <catch2/catch_test_macros.hpp>
+
 #include <aoc/framework/Solver.hpp>
+#include <aoc/framework/SolverEngine.hpp>
 
 class TestContext
 {
 public:
-    void run(const std::unique_ptr<Solver<long long, long long>>&& solver, const long long expected1,
-        const long long expected2, const std::vector<std::string>& inputPaths);
-    void run(const std::unique_ptr<Solver<long long, std::string>>&& solver, const long long expected1,
-        const std::string expected2, const std::vector<std::string>& inputPaths);
-    void run(const std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string expected1,
-        const long long expected2, const std::vector<std::string>& inputPaths);
-    void runPart1(const std::unique_ptr<Solver<long long, long long>>&& solver, const long long expected,
+    void run(std::unique_ptr<Solver<long long, long long>>&& solver, const long long& expected1,
+        const long long& expected2, const std::vector<std::string>& inputPaths);
+    void run(std::unique_ptr<Solver<long long, std::string>>&& solver, const long long& expected1,
+        const std::string& expected2, const std::vector<std::string>& inputPaths);
+    void run(std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string& expected1,
+        const long long& expected2, const std::vector<std::string>& inputPaths);
+    void runPart1(std::unique_ptr<Solver<long long, long long>>&& solver, const long long& expected,
         const std::vector<std::string>& inputPaths);
-    void runPart1(const std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string expected,
+    void runPart1(std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string& expected,
         const std::vector<std::string>& inputPaths);
-    void runPart2(const std::unique_ptr<Solver<long long, long long>>&& solver, const long long expected,
+    void runPart2(std::unique_ptr<Solver<long long, long long>>&& solver, const long long& expected,
         const std::vector<std::string>& inputPaths);
     std::vector<std::string> getInputPaths() const;
     std::vector<std::string> getExampleInputPaths() const;
+private:
+    template <typename T1, typename T2>
+    void runGeneric(const std::unique_ptr<Solver<T1, T2>>&& solver, const T1& expected1, const T2& expected2,
+        const std::vector<std::string>& inputPaths)
+    {
+        SolverEngine solverEngine{ inputPaths };
+        solverEngine.run(*solver);
+
+        REQUIRE(expected1 == solver->getResultPart1());
+        REQUIRE(expected2 == solver->getResultPart2());
+    }
+
+    template <typename T1, typename T2>
+    void runPart1Generic(const std::unique_ptr<Solver<T1, T2>>&& solver, const T1& expected,
+        const std::vector<std::string>& inputPaths)
+    {
+        SolverEngine solverEngine{ inputPaths };
+        solverEngine.run(*solver);
+
+        REQUIRE(expected == solver->getResultPart1());
+    }
+
+    template <typename T1, typename T2>
+    void runPart2Generic(const std::unique_ptr<Solver<T1, T2>>&& solver, const T2& expected,
+        const std::vector<std::string>& inputPaths)
+    {
+        SolverEngine solverEngine{ inputPaths };
+        solverEngine.run(*solver);
+
+        REQUIRE(expected == solver->getResultPart2());
+    }
 };
diff --git a/tests/src/TestContext.cpp b/tests/src/TestContext.cpp
index 22bbb76..078c536 100644
--- a/tests/src/TestContext.cpp
+++ b/tests/src/TestContext.cpp
@@ -15,65 +15,40 @@
 
 #include <aocTests/TestContext.hpp>
 
-#include <catch2/catch_test_macros.hpp>
-
-#include <aoc/framework/SolverEngine.hpp>
-
-void TestContext::run(const std::unique_ptr<Solver<long long, long long>>&& solver, const long long expected1,
-    const long long expected2, const std::vector<std::string>& inputPaths)
+void TestContext::run(std::unique_ptr<Solver<long long, long long>>&& solver, const long long& expected1,
+    const long long& expected2, const std::vector<std::string>& inputPaths)
 {
-    SolverEngine solverEngine{ inputPaths };
-    solverEngine.run(*solver);
-
-    REQUIRE(expected1 == solver->getResultPart1());
-    REQUIRE(expected2 == solver->getResultPart2());
+    runGeneric(std::move(solver), expected1, expected2, inputPaths);
 }
 
-void TestContext::run(const std::unique_ptr<Solver<long long, std::string>>&& solver, const long long expected1,
-    const std::string expected2, const std::vector<std::string>& inputPaths)
+void TestContext::run(std::unique_ptr<Solver<long long, std::string>>&& solver, const long long& expected1,
+    const std::string& expected2, const std::vector<std::string>& inputPaths)
 {
-    SolverEngine solverEngine{ inputPaths };
-    solverEngine.run(*solver);
-
-    REQUIRE(expected1 == solver->getResultPart1());
-    REQUIRE(expected2 == solver->getResultPart2());
+    runGeneric(std::move(solver), expected1, expected2, inputPaths);
 }
 
-void TestContext::run(const std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string expected1,
-    const long long expected2, const std::vector<std::string>& inputPaths)
+void TestContext::run(std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string& expected1,
+    const long long& expected2, const std::vector<std::string>& inputPaths)
 {
-    SolverEngine solverEngine{ inputPaths };
-    solverEngine.run(*solver);
-
-    REQUIRE(expected1 == solver->getResultPart1());
-    REQUIRE(expected2 == solver->getResultPart2());
+    runGeneric(std::move(solver), expected1, expected2, inputPaths);
 }
 
-void TestContext::runPart1(const std::unique_ptr<Solver<long long, long long>>&& solver, const long long expected,
+void TestContext::runPart1(std::unique_ptr<Solver<long long, long long>>&& solver, const long long& expected,
     const std::vector<std::string>& inputPaths)
 {
-    SolverEngine solverEngine{ inputPaths };
-    solverEngine.run(*solver);
-
-    REQUIRE(expected == solver->getResultPart1());
+    runPart1Generic(std::move(solver), expected, inputPaths);
 }
 
-void TestContext::runPart1(const std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string expected,
+void TestContext::runPart1(std::unique_ptr<Solver<std::string, long long>>&& solver, const std::string& expected,
     const std::vector<std::string>& inputPaths)
 {
-    SolverEngine solverEngine{ inputPaths };
-    solverEngine.run(*solver);
-
-    REQUIRE(expected == solver->getResultPart1());
+    runPart1Generic(std::move(solver), expected, inputPaths);
 }
 
-void TestContext::runPart2(const std::unique_ptr<Solver<long long, long long>>&& solver, const long long expected,
+void TestContext::runPart2(std::unique_ptr<Solver<long long, long long>>&& solver, const long long& expected,
     const std::vector<std::string>& inputPaths)
 {
-    SolverEngine solverEngine{ inputPaths };
-    solverEngine.run(*solver);
-
-    REQUIRE(expected == solver->getResultPart2());
+    runPart2Generic(std::move(solver), expected, inputPaths);
 }
 
 std::vector<std::string> TestContext::getInputPaths() const