diff --git a/Source/CollisionDetection/VisualTesting/imstkBoxVsBoxSurfaceMeshTest.cpp b/Source/CollisionDetection/VisualTesting/imstkBoxVsBoxSurfaceMeshTest.cpp
index e0eb12a537158e9d61114ab8223720146784efce..62525cccad3aee2114b7c84dc54891d6306ac265 100644
--- a/Source/CollisionDetection/VisualTesting/imstkBoxVsBoxSurfaceMeshTest.cpp
+++ b/Source/CollisionDetection/VisualTesting/imstkBoxVsBoxSurfaceMeshTest.cpp
@@ -20,19 +20,11 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCollidingObject.h"
-#include "imstkCollisionDataDebugObject.h"
+#include "imstkCollisionDetectionVisualTest.h"
 #include "imstkGeometryUtilities.h"
-#include "imstkKeyboardDeviceClient.h"
 #include "imstkMeshToMeshBruteForceCD.h"
 #include "imstkOrientedBox.h"
-#include "imstkRenderMaterial.h"
-#include "imstkScene.h"
-#include "imstkSimulationManager.h"
 #include "imstkSurfaceMesh.h"
-#include "imstkVisualModel.h"
-#include "imstkVisualTestingUtils.h"
-#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -40,114 +32,33 @@ using namespace imstk;
 /// \brief This test is used to investigate Triangle Vs Triangle collision
 /// of the MeshToMeshBruteForceCD method.
 /// It displays the collision data, and allows users to investigate various cases
-/// by moving the geometry around with keyboard controls i,j,k,l,o,u
 ///
-TEST_F(VisualTestManager, BoxVsBoxSurfaceMesh)
+TEST_F(CollisionDetectionVisualTest, BoxVsBoxSurfaceMesh)
 {
+    m_camera = std::make_shared<Camera>();
+    m_camera->setFocalPoint(-0.0366287, 0.420204, 0.474284);
+    m_camera->setPosition(-2.60143, 1.23713, 2.42823);
+    m_camera->setViewUp(0.216266, 0.968787, -0.121162);
+
     // Create a box mesh
     auto box1 = std::make_shared<OrientedBox>(
         Vec3d::Zero(), Vec3d(0.5, 0.5, 0.5), Quatd::Identity());
     auto box2 = std::make_shared<OrientedBox>(
         Vec3d::Zero(), Vec3d(0.4, 0.4, 0.4), Quatd::Identity());
 
-    std::shared_ptr<SurfaceMesh> box1Mesh = GeometryUtils::toSurfaceMesh(box1);
-    std::shared_ptr<SurfaceMesh> box2Mesh = GeometryUtils::toSurfaceMesh(box2);
-    box2Mesh->rotate(Vec3d(0.0, 0.0, 1.0), PI_2 * 0.5);
-    box2Mesh->rotate(Vec3d(1.0, 0.0, 0.0), PI_2 * 0.5);
-    box2Mesh->translate(Vec3d(0.0, 0.8, 0.8));
-
-    // Setup the scene
-    m_scene = std::make_shared<Scene>("BoxBoxMeshTest");
-    m_scene->getActiveCamera()->setPosition(0.073, 1.743, 3.679);
-    m_scene->getActiveCamera()->setFocalPoint(0.333, 0.333, 0.25);
-    m_scene->getActiveCamera()->setViewUp(0.041, 0.928, -0.371);
-
-    auto obj1 = std::make_shared<CollidingObject>("obj1");
-    obj1->setVisualGeometry(box1Mesh);
-    obj1->setCollidingGeometry(box1Mesh);
-    obj1->getVisualModel(0)->getRenderMaterial()->setOpacity(0.5);
-    obj1->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    m_scene->addSceneObject(obj1);
-
-    auto obj2 = std::make_shared<CollidingObject>("obj2");
-    obj2->setVisualGeometry(box2Mesh);
-    obj2->setCollidingGeometry(box2Mesh);
-    obj2->getVisualModel(0)->getRenderMaterial()->setOpacity(0.5);
-    obj2->getVisualModel(0)->getRenderMaterial()->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
-    m_scene->addSceneObject(obj2);
+    m_cdGeom1 = GeometryUtils::toSurfaceMesh(box1);
+    m_cdGeom2 = GeometryUtils::toSurfaceMesh(box2);
+    m_cdGeom2->rotate(Vec3d(0.0, 0.0, 1.0), PI_2 * 0.5);
+    m_cdGeom2->rotate(Vec3d(1.0, 0.0, 0.0), PI_2 * 0.5);
+    m_cdGeom2->translate(Vec3d(0.0, 0.8, 0.8));
 
     auto cd = std::make_shared<MeshToMeshBruteForceCD>();
-    cd->setInputGeometryA(box1Mesh);
-    cd->setInputGeometryB(box2Mesh);
+    cd->setInputGeometryA(m_cdGeom1);
+    cd->setInputGeometryB(m_cdGeom2);
     cd->setGenerateEdgeEdgeContacts(true);
     cd->update();
+    m_collisionMethod = cd;
 
-    // Debug Collision Geometry
-    auto cdDebugObj = std::make_shared<CollisionDataDebugObject>();
-    cdDebugObj->setInputCD(cd->getCollisionData());
-    cdDebugObj->setPrintContacts(true);
-    m_scene->addSceneObject(cdDebugObj);
-
-    std::cout << "================================================\n";
-    std::cout << "Key i/j/k/u/o move the cube\n";
-    std::cout << "Key 1/2/3/4 rotate the cube\n";
-    std::cout << "================================================\n\n";
-
-    connect<KeyEvent>(m_viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
-        [&](KeyEvent* e)
-        {
-            const double s = 0.05;
-            if (e->m_key == 'i')
-            {
-                box2Mesh->translate(Vec3d(0.0, 0.0, 1.0) * s);
-            }
-            else if (e->m_key == 'k')
-            {
-                box2Mesh->translate(Vec3d(0.0, 0.0, -1.0) * s);
-            }
-            else if (e->m_key == 'j')
-            {
-                box2Mesh->translate(Vec3d(-1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'l')
-            {
-                box2Mesh->translate(Vec3d(1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'u')
-            {
-                box2Mesh->translate(Vec3d(0.0, -1.0, 0.0) * s);
-            }
-            else if (e->m_key == 'o')
-            {
-                box2Mesh->translate(Vec3d(0.0, 1.0, 0.0) * s);
-            }
-            else if (e->m_key == '1')
-            {
-                box2Mesh->rotate(Vec3d(0.0, 0.0, 1.0), 0.1);
-            }
-            else if (e->m_key == '2')
-            {
-                box2Mesh->rotate(Vec3d(0.0, 0.0, 1.0), -0.1);
-            }
-            else if (e->m_key == '3')
-            {
-                box2Mesh->rotate(Vec3d(0.0, 1.0, 0.0), 0.1);
-            }
-            else if (e->m_key == '4')
-            {
-                box2Mesh->rotate(Vec3d(0.0, 1.0, 0.0), -0.1);
-            }
-            // Immediately update the geometry, recompute the CD, update CD debug geometry
-            box2Mesh->postModified();
-            box2Mesh->updatePostTransformData();
-            cd->update();
-            cdDebugObj->debugUpdate();
-        });
-    connect<Event>(m_driver, &SimulationManager::starting,
-        [&](Event*)
-        {
-            cdDebugObj->debugUpdate();
-        });
-
+    createScene();
     runFor(2.0);
 }
\ No newline at end of file
diff --git a/Source/CollisionDetection/VisualTesting/imstkCollisionDetectionVisualTest.cpp b/Source/CollisionDetection/VisualTesting/imstkCollisionDetectionVisualTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e900836e27166177d3ba82fc9b3031f8b7418523
--- /dev/null
+++ b/Source/CollisionDetection/VisualTesting/imstkCollisionDetectionVisualTest.cpp
@@ -0,0 +1,184 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkCollisionDetectionVisualTest.h"
+#include "imstkCamera.h"
+#include "imstkCollidingObject.h"
+#include "imstkCollisionDataDebugObject.h"
+#include "imstkCollisionDetectionAlgorithm.h"
+#include "imstkDirectionalLight.h"
+#include "imstkGeometry.h"
+#include "imstkKeyboardDeviceClient.h"
+#include "imstkRenderMaterial.h"
+#include "imstkScene.h"
+#include "imstkSimulationManager.h"
+#include "imstkVisualModel.h"
+#include "imstkVTKViewer.h"
+
+using namespace imstk;
+
+void
+CollisionDetectionVisualTest::SetUp()
+{
+    VisualTest::SetUp();
+
+    auto defaultMaterial = std::make_shared<RenderMaterial>();
+    defaultMaterial->setOpacity(0.5);
+    defaultMaterial->setBackFaceCulling(false);
+    defaultMaterial->setDisplayMode(RenderMaterial::DisplayMode::WireframeSurface);
+
+    m_cdObj1 = std::make_shared<CollidingObject>("cdObj1");
+    auto model1 = std::make_shared<VisualModel>();
+    model1->setRenderMaterial(defaultMaterial);
+    m_cdObj1->addVisualModel(model1);
+
+    m_cdObj2 = std::make_shared<CollidingObject>("cdObj2");
+    auto model2 = std::make_shared<VisualModel>();
+    model2->setRenderMaterial(defaultMaterial);
+    m_cdObj2->addVisualModel(model2);
+}
+
+void
+CollisionDetectionVisualTest::createScene()
+{
+    // Setup the scene
+    m_scene = std::make_shared<Scene>(::testing::UnitTest::GetInstance()->current_test_info()->name());
+    if (m_camera != nullptr)
+    {
+        *m_scene->getActiveCamera() = *m_camera;
+    }
+
+    ASSERT_NE(m_cdGeom1, nullptr) <<
+        "Missing a m_cdGeom1 Geometry for CollisionDetectionVisualTest";
+    ASSERT_NE(m_cdObj1, nullptr) <<
+        "Missing a m_cdObj1 CollidingObject for CollisionDetectionVisualTest";
+    m_cdObj1->getVisualModel(0)->setGeometry(m_cdGeom1);
+    m_cdObj1->setCollidingGeometry(m_cdGeom1);
+    m_scene->addSceneObject(m_cdObj1);
+
+    ASSERT_NE(m_cdGeom2, nullptr) <<
+        "Missing a m_cdGeom2 Geometry for CollisionDetectionVisualTest";
+    ASSERT_NE(m_cdObj2, nullptr) <<
+        "Missing a m_cdObj2 CollidingObject for CollisionDetectionVisualTest";
+    m_cdObj2->getVisualModel(0)->setGeometry(m_cdGeom2);
+    m_cdObj2->setCollidingGeometry(m_cdGeom2);
+    m_scene->addSceneObject(m_cdObj2);
+
+    ASSERT_NE(m_collisionMethod, nullptr) <<
+        "Missing a m_collisionMethod CollisionDetectionAlgorithm for CollisionDetectionVisualTest";
+
+    // Debug geometry to visualize collision data
+    m_cdDebugObject = std::make_shared<CollisionDataDebugObject>();
+    m_cdDebugObject->setInputCD(m_collisionMethod->getCollisionData());
+    m_cdDebugObject->setPrintContacts(m_printContacts);
+    m_scene->addSceneObject(m_cdDebugObject);
+
+    connect<KeyEvent>(m_viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
+        [this](KeyEvent* e)
+        {
+            bool moved = false;
+            // Transform & immediately update post transform geometry
+            if (m_geom1Moveable && moveGeometryByKey(e->m_key, m_cdGeom1))
+            {
+                moved = true;
+            }
+            if (m_geom2Moveable && moveGeometryByKey(e->m_key, m_cdGeom2))
+            {
+                moved = true;
+            }
+            if (moved)
+            {
+                // Recompute the CD & update debug CD object
+                m_collisionMethod->update();
+                m_cdDebugObject->debugUpdate();
+            }
+        });
+    connect<Event>(m_driver, &SimulationManager::starting,
+        [&](Event*)
+        {
+            m_cdDebugObject->debugUpdate();
+        });
+
+    // Light
+    auto light = std::make_shared<DirectionalLight>();
+    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
+    light->setIntensity(1.0);
+    m_scene->addLight("Light", light);
+}
+
+bool
+CollisionDetectionVisualTest::moveGeometryByKey(const unsigned char       key,
+                                                std::shared_ptr<Geometry> geom)
+{
+    const Mat4d  initTransform = geom->getTransform();
+    const double s = 0.05;
+    if (key == 'i')
+    {
+        geom->translate(Vec3d(0.0, 0.0, 1.0) * s);
+    }
+    else if (key == 'k')
+    {
+        geom->translate(Vec3d(0.0, 0.0, -1.0) * s);
+    }
+    else if (key == 'j')
+    {
+        geom->translate(Vec3d(-1.0, 0.0, 0.0) * s);
+    }
+    else if (key == 'l')
+    {
+        geom->translate(Vec3d(1.0, 0.0, 0.0) * s);
+    }
+    else if (key == 'u')
+    {
+        geom->translate(Vec3d(0.0, -1.0, 0.0) * s);
+    }
+    else if (key == 'o')
+    {
+        geom->translate(Vec3d(0.0, 1.0, 0.0) * s);
+    }
+    else if (key == '1')
+    {
+        geom->rotate(Vec3d(0.0, 0.0, 1.0), 0.1);
+    }
+    else if (key == '2')
+    {
+        geom->rotate(Vec3d(0.0, 0.0, 1.0), -0.1);
+    }
+    else if (key == '3')
+    {
+        geom->rotate(Vec3d(0.0, 1.0, 0.0), 0.1);
+    }
+    else if (key == '4')
+    {
+        geom->rotate(Vec3d(0.0, 1.0, 0.0), -0.1);
+    }
+
+    if (initTransform != geom->getTransform())
+    {
+        geom->postModified();
+        geom->updatePostTransformData();
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/Source/CollisionDetection/VisualTesting/imstkCollisionDetectionVisualTest.h b/Source/CollisionDetection/VisualTesting/imstkCollisionDetectionVisualTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..75006694c64c5d738b02d5bdd799870d23c3ce19
--- /dev/null
+++ b/Source/CollisionDetection/VisualTesting/imstkCollisionDetectionVisualTest.h
@@ -0,0 +1,75 @@
+/*=========================================================================
+
+   Library: iMSTK
+
+   Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
+   & Imaging in Medicine, Rensselaer Polytechnic Institute.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+=========================================================================*/
+
+#include "imstkVisualTestingUtils.h"
+
+namespace imstk
+{
+class Camera;
+class CollisionDataDebugObject;
+class CollisionDetectionAlgorithm;
+class CollidingObject;
+class Geometry;
+class KeyEvent;
+} // namespace imstk
+
+using namespace imstk;
+
+///
+/// \class CollisionDetectionVisualTest
+///
+/// \brief Test that involves two collision geometries and a collision method
+///
+class CollisionDetectionVisualTest : public VisualTest
+{
+public:
+    void SetUp() override;
+
+    ///
+    /// \brief Create a scene composed of two collision objects with
+    /// the respective collision geometries and method
+    ///
+    void createScene();
+
+    ///
+    /// \brief Adds the default scheme for key controls
+    /// \param Key code
+    /// \param Geometry to move
+    /// \return Whether or not geom was moved
+    ///
+    bool moveGeometryByKey(const unsigned char       key,
+                           std::shared_ptr<Geometry> geom);
+
+public:
+    std::shared_ptr<CollidingObject> m_cdObj2 = nullptr;
+    std::shared_ptr<CollidingObject> m_cdObj1 = nullptr;
+    std::shared_ptr<Geometry> m_cdGeom1       = nullptr;
+    std::shared_ptr<Geometry> m_cdGeom2       = nullptr;
+
+    std::shared_ptr<Camera> m_camera = nullptr;
+
+    std::shared_ptr<CollisionDetectionAlgorithm> m_collisionMethod = nullptr;
+    std::shared_ptr<CollisionDataDebugObject>    m_cdDebugObject   = nullptr;
+
+    bool m_geom1Moveable = false;
+    bool m_geom2Moveable = true;
+    bool m_printContacts = false;
+};
\ No newline at end of file
diff --git a/Source/CollisionDetection/VisualTesting/imstkImplicitGeometryVsSurfaceMeshTest.cpp b/Source/CollisionDetection/VisualTesting/imstkImplicitGeometryVsSurfaceMeshTest.cpp
index f54a83df0b2b5eb4767c18f876b563169b839977..d31fbdd034039014f0d5b4f0f2b9ec6ee77ded99 100644
--- a/Source/CollisionDetection/VisualTesting/imstkImplicitGeometryVsSurfaceMeshTest.cpp
+++ b/Source/CollisionDetection/VisualTesting/imstkImplicitGeometryVsSurfaceMeshTest.cpp
@@ -20,21 +20,11 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCollidingObject.h"
-#include "imstkCollisionDataDebugObject.h"
-#include "imstkDirectionalLight.h"
-#include "imstkImplicitGeometry.h"
+#include "imstkCollisionDetectionVisualTest.h"
 #include "imstkImplicitGeometryToPointSetCD.h"
-#include "imstkKeyboardDeviceClient.h"
 #include "imstkPlane.h"
-#include "imstkRenderMaterial.h"
-#include "imstkScene.h"
-#include "imstkSimulationManager.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkVecDataArray.h"
-#include "imstkVisualModel.h"
-#include "imstkVisualTestingUtils.h"
-#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -42,102 +32,39 @@ using namespace imstk;
 /// \brief This test is used to investigate ImplicitGeometry Vs SurfaceMesh collision
 /// of the ImplicitGeometryToPointSet method.
 /// It displays the collision data, and allows users to investigate various cases
-/// by moving the geometry around with keyboard controls i,j,k,l,o,u
 ///
-TEST_F(VisualTestManager, ImplicitGeometryVsSurfaceMesh)
+TEST_F(CollisionDetectionVisualTest, ImplicitGeometryVsSurfaceMesh)
 {
-    // Setup the scene
-    m_scene = std::make_shared<Scene>("ImplicitGeometryVsSurfaceMesh");
-    m_scene->getActiveCamera()->setPosition(0.18, 1.08, 1.34);
-    m_scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
-    m_scene->getActiveCamera()->setViewUp(0.011, 0.78, -0.63);
+    m_camera = std::make_shared<Camera>();
+    m_camera->setPosition(0.18, 1.08, 1.34);
+    m_camera->setFocalPoint(0.0, 0.0, 0.0);
+    m_camera->setViewUp(0.011, 0.78, -0.63);
 
-    auto                    obj1 = std::make_shared<CollidingObject>("obj1");
-    auto                    triangleMesh1 = std::make_shared<SurfaceMesh>();
-    VecDataArray<double, 3> triangleVertices1(3);
-    triangleVertices1[0] = Vec3d(0.1, -0.5, 0.0);
-    triangleVertices1[1] = Vec3d(0.1, 0.5, 0.0);
-    triangleVertices1[2] = Vec3d(-0.5, 0.0, 0.0);
-    VecDataArray<int, 3> triangleIndices1(1);
-    triangleIndices1[0] = Vec3i(0, 1, 2);
-    triangleMesh1->initialize(
-        std::make_shared<VecDataArray<double, 3>>(triangleVertices1),
-        std::make_shared<VecDataArray<int, 3>>(triangleIndices1));
-    obj1->setVisualGeometry(triangleMesh1);
-    obj1->setCollidingGeometry(triangleMesh1);
-    obj1->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
-    m_scene->addSceneObject(obj1);
-
-    auto obj2 = std::make_shared<CollidingObject>("obj2");
     auto implicitGeom = std::make_shared<Plane>();
     implicitGeom->setNormal(0.0, 1.0, 0.0);
     implicitGeom->setPosition(0.0, 0.0, 0.0);
     implicitGeom->setWidth(0.5);
-    obj2->setVisualGeometry(implicitGeom);
-    obj2->setCollidingGeometry(implicitGeom);
-    obj2->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
-    m_scene->addSceneObject(obj2);
+    m_cdGeom1 = implicitGeom;
+
+    auto                    triangleMesh = std::make_shared<SurfaceMesh>();
+    VecDataArray<double, 3> triangleVertices(3);
+    triangleVertices[0] = Vec3d(0.1, -0.5, 0.0);
+    triangleVertices[1] = Vec3d(0.1, 0.5, 0.0);
+    triangleVertices[2] = Vec3d(-0.5, 0.0, 0.0);
+    VecDataArray<int, 3> triangleIndices(1);
+    triangleIndices[0] = Vec3i(0, 1, 2);
+    triangleMesh->initialize(
+        std::make_shared<VecDataArray<double, 3>>(triangleVertices),
+        std::make_shared<VecDataArray<int, 3>>(triangleIndices));
+    m_cdGeom2 = triangleMesh;
 
     auto cd = std::make_shared<ImplicitGeometryToPointSetCD>();
     cd->setGenerateCD(true, true);
-    cd->setInputGeometryA(triangleMesh1);
+    cd->setInputGeometryA(triangleMesh);
     cd->setInputGeometryB(implicitGeom);
     cd->update();
+    m_collisionMethod = cd;
 
-    // Debug geometry to visualize collision data
-    auto cdDebugObj = std::make_shared<CollisionDataDebugObject>();
-    cdDebugObj->setInputCD(cd->getCollisionData());
-    cdDebugObj->setPrintContacts(true);
-    m_scene->addSceneObject(cdDebugObj);
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>();
-    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
-    light->setIntensity(1.0);
-    m_scene->addLight("Light", light);
-
-    std::cout << "================================================\n";
-    std::cout << "Key i/j/k/u/o move the triangle\n";
-    std::cout << "================================================\n\n";
-
-    connect<KeyEvent>(m_viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
-        [&](KeyEvent* e)
-        {
-            const double s = 0.05;
-            if (e->m_key == 'i')
-            {
-                triangleMesh1->translate(Vec3d(0.0, 0.0, 1.0) * s);
-            }
-            else if (e->m_key == 'k')
-            {
-                triangleMesh1->translate(Vec3d(0.0, 0.0, -1.0) * s);
-            }
-            else if (e->m_key == 'j')
-            {
-                triangleMesh1->translate(Vec3d(-1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'l')
-            {
-                triangleMesh1->translate(Vec3d(1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'u')
-            {
-                triangleMesh1->translate(Vec3d(0.0, -1.0, 0.0) * s);
-            }
-            else if (e->m_key == 'o')
-            {
-                triangleMesh1->translate(Vec3d(0.0, 1.0, 0.0) * s);
-            }
-            triangleMesh1->postModified();
-            triangleMesh1->updatePostTransformData();
-            cd->update();
-            cdDebugObj->debugUpdate();
-        });
-   connect<Event>(m_driver, &SimulationManager::starting,
-        [&](Event*)
-        {
-            cdDebugObj->debugUpdate();
-        });
-
+    createScene();
     runFor(2.0);
 }
\ No newline at end of file
diff --git a/Source/CollisionDetection/VisualTesting/imstkTriangleVsSphereTest.cpp b/Source/CollisionDetection/VisualTesting/imstkTriangleVsSphereTest.cpp
index 8cb68c8696b174b65c3185b74772c7ef98b39fed..aa67cdd5ac8a1585deeb81c2fdf2fddbcdb8428f 100644
--- a/Source/CollisionDetection/VisualTesting/imstkTriangleVsSphereTest.cpp
+++ b/Source/CollisionDetection/VisualTesting/imstkTriangleVsSphereTest.cpp
@@ -21,19 +21,13 @@
 
 #include "imstkCamera.h"
 #include "imstkCollidingObject.h"
-#include "imstkCollisionDataDebugObject.h"
-#include "imstkDirectionalLight.h"
-#include "imstkKeyboardDeviceClient.h"
+#include "imstkCollisionDetectionVisualTest.h"
 #include "imstkRenderMaterial.h"
-#include "imstkScene.h"
-#include "imstkSimulationManager.h"
 #include "imstkSphere.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkSurfaceMeshToSphereCD.h"
 #include "imstkVecDataArray.h"
 #include "imstkVisualModel.h"
-#include "imstkVisualTestingUtils.h"
-#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -41,18 +35,20 @@ using namespace imstk;
 /// \brief This test is used to investigate Triangle Vs Sphere collision
 /// of the SurfaceMeshToSphereCD method
 /// It displays the collision data, and allows users to investigate various cases
-/// by moving the geometry around with keyboard controls i,j,k,l,o,u
 ///
-TEST_F(VisualTestManager, TriangleVsSphere)
+TEST_F(CollisionDetectionVisualTest, TriangleVsSphere)
 {
-    // Setup the scene
-    m_scene = std::make_shared<Scene>("TriangleVsSphereTest");
-    m_scene->getActiveCamera()->setPosition(0, 2.74, 2.69);
-    m_scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
-    m_scene->getActiveCamera()->setViewUp(0, 0.71, -0.71);
+    m_camera = std::make_shared<Camera>();
+    m_camera->setPosition(0, 2.74, 2.69);
+    m_camera->setFocalPoint(0.0, 0.0, 0.0);
+    m_camera->setViewUp(0, 0.71, -0.71);
+
+    m_cdGeom1 = std::make_shared<Sphere>(Vec3d(0.0, 0.0, 0.0), 1.0);
+    m_cdObj1->getVisualModel(0)->getRenderMaterial()->setDisplayMode(
+        RenderMaterial::DisplayMode::Surface);
+
+    auto triangleMesh = std::make_shared<SurfaceMesh>();
 
-    auto                    obj1 = std::make_shared<CollidingObject>("obj1");
-    auto                    triangleMesh = std::make_shared<SurfaceMesh>();
     VecDataArray<double, 3> triangleVertices(3);
     triangleVertices[0] = Vec3d(-0.5, 0.9, -0.5);
     triangleVertices[1] = Vec3d(0.5, 0.9, -0.5);
@@ -62,77 +58,13 @@ TEST_F(VisualTestManager, TriangleVsSphere)
     triangleMesh->initialize(
         std::make_shared<VecDataArray<double, 3>>(triangleVertices),
         std::make_shared<VecDataArray<int, 3>>(triangleIndices));
-    obj1->setVisualGeometry(triangleMesh);
-    obj1->setCollidingGeometry(triangleMesh);
-    obj1->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
-    m_scene->addSceneObject(obj1);
-
-    auto obj2   = std::make_shared<CollidingObject>("obj2");
-    auto sphere = std::make_shared<Sphere>(Vec3d(0.0, 0.0, 0.0), 1.0);
-    obj2->setVisualGeometry(sphere);
-    obj2->setCollidingGeometry(sphere);
-    obj2->getVisualModel(0)->getRenderMaterial()->setOpacity(0.5);
-    m_scene->addSceneObject(obj2);
-
-    auto cd = std::make_shared<SurfaceMeshToSphereCD>();
-    cd->setInputGeometryA(triangleMesh);
-    cd->setInputGeometryB(sphere);
-    cd->update();
-
-    // Debug geometry
-    auto cdDebugObj = std::make_shared<CollisionDataDebugObject>();
-    cdDebugObj->setInputCD(cd->getCollisionData());
-    cdDebugObj->setPrintContacts(true);
-    m_scene->addSceneObject(cdDebugObj);
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>();
-    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
-    light->setIntensity(1.0);
-    m_scene->addLight("Light", light);
-
-    std::cout << "================================================\n";
-    std::cout << "Key i/j/k/u/o move the triangle\n";
-    std::cout << "================================================\n\n";
+    m_cdGeom2 = triangleMesh;
 
-    connect<KeyEvent>(m_viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
-        [&](KeyEvent* e)
-        {
-            const double s = 0.05;
-            if (e->m_key == 'i')
-            {
-                triangleMesh->translate(Vec3d(0.0, 0.0, 1.0) * s);
-            }
-            else if (e->m_key == 'k')
-            {
-                triangleMesh->translate(Vec3d(0.0, 0.0, -1.0) * s);
-            }
-            else if (e->m_key == 'j')
-            {
-                triangleMesh->translate(Vec3d(-1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'l')
-            {
-                triangleMesh->translate(Vec3d(1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'u')
-            {
-                triangleMesh->translate(Vec3d(0.0, -1.0, 0.0) * s);
-            }
-            else if (e->m_key == 'o')
-            {
-                triangleMesh->translate(Vec3d(0.0, 1.0, 0.0) * s);
-            }
-            triangleMesh->postModified();
-            triangleMesh->updatePostTransformData();
-            cd->update();
-            cdDebugObj->debugUpdate();
-        });
-    connect<Event>(m_driver, &SimulationManager::starting,
-        [&](Event*)
-        {
-            cdDebugObj->debugUpdate();
-        });
+    m_collisionMethod = std::make_shared<SurfaceMeshToSphereCD>();
+    m_collisionMethod->setInputGeometryA(m_cdGeom2);
+    m_collisionMethod->setInputGeometryB(m_cdGeom1);
+    m_collisionMethod->update();
 
+    createScene();
     runFor(2.0);
 }
\ No newline at end of file
diff --git a/Source/CollisionDetection/VisualTesting/imstkTriangleVsTriangleTest.cpp b/Source/CollisionDetection/VisualTesting/imstkTriangleVsTriangleTest.cpp
index 69395c62863504ebad1714decece1527d48e6c27..fc6bd0e69423852195d7c98d87e7977a38702fa0 100644
--- a/Source/CollisionDetection/VisualTesting/imstkTriangleVsTriangleTest.cpp
+++ b/Source/CollisionDetection/VisualTesting/imstkTriangleVsTriangleTest.cpp
@@ -20,19 +20,10 @@
 =========================================================================*/
 
 #include "imstkCamera.h"
-#include "imstkCollidingObject.h"
-#include "imstkCollisionDataDebugObject.h"
-#include "imstkDirectionalLight.h"
-#include "imstkKeyboardDeviceClient.h"
-#include "imstkRenderMaterial.h"
-#include "imstkScene.h"
-#include "imstkSimulationManager.h"
+#include "imstkCollisionDetectionVisualTest.h"
 #include "imstkSurfaceMesh.h"
 #include "imstkSurfaceMeshToSurfaceMeshCD.h"
 #include "imstkVecDataArray.h"
-#include "imstkVisualModel.h"
-#include "imstkVisualTestingUtils.h"
-#include "imstkVTKViewer.h"
 
 using namespace imstk;
 
@@ -40,17 +31,14 @@ using namespace imstk;
 /// \brief This test is used to investigate Triangle Vs Triangle collision
 /// of the SurfaceMeshToSurfaceMeshCD method.
 /// It displays the collision data, and allows users to investigate various cases
-/// by moving the geometry around with keyboard controls i,j,k,l,o,u
 ///
-TEST_F(VisualTestManager, TriangleVsTriangle)
+TEST_F(CollisionDetectionVisualTest, TriangleVsTriangle)
 {
-    // Setup the scene
-    m_scene = std::make_shared<Scene>("TriangleVsTriangleTest");
-    m_scene->getActiveCamera()->setPosition(0.18, 1.08, 1.34);
-    m_scene->getActiveCamera()->setFocalPoint(0.0, 0.0, 0.0);
-    m_scene->getActiveCamera()->setViewUp(0.011, 0.78, -0.63);
+    m_camera = std::make_shared<Camera>();
+    m_camera->setPosition(0.18, 1.08, 1.34);
+    m_camera->setFocalPoint(0.0, 0.0, 0.0);
+    m_camera->setViewUp(0.011, 0.78, -0.63);
 
-    auto                    obj1 = std::make_shared<CollidingObject>("obj1");
     auto                    triangleMesh1 = std::make_shared<SurfaceMesh>();
     VecDataArray<double, 3> triangleVertices1(3);
     triangleVertices1[0] = Vec3d(0.1, 0.0, -0.5);
@@ -61,12 +49,8 @@ TEST_F(VisualTestManager, TriangleVsTriangle)
     triangleMesh1->initialize(
         std::make_shared<VecDataArray<double, 3>>(triangleVertices1),
         std::make_shared<VecDataArray<int, 3>>(triangleIndices1));
-    obj1->setVisualGeometry(triangleMesh1);
-    obj1->setCollidingGeometry(triangleMesh1);
-    obj1->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
-    m_scene->addSceneObject(obj1);
+    m_cdGeom1 = triangleMesh1;
 
-    auto                    obj2 = std::make_shared<CollidingObject>("obj2");
     auto                    triangleMesh2 = std::make_shared<SurfaceMesh>();
     VecDataArray<double, 3> triangleVertices2(3);
     triangleVertices2[0] = Vec3d(-0.1, 0.5, 0.0);
@@ -77,70 +61,13 @@ TEST_F(VisualTestManager, TriangleVsTriangle)
     triangleMesh2->initialize(
         std::make_shared<VecDataArray<double, 3>>(triangleVertices2),
         std::make_shared<VecDataArray<int, 3>>(triangleIndices2));
-    obj2->setVisualGeometry(triangleMesh2);
-    obj2->setCollidingGeometry(triangleMesh2);
-    obj2->getVisualModel(0)->getRenderMaterial()->setBackFaceCulling(false);
-    m_scene->addSceneObject(obj2);
+    m_cdGeom2 = triangleMesh2;
 
-    auto cd = std::make_shared<SurfaceMeshToSurfaceMeshCD>();
-    cd->setInputGeometryA(triangleMesh1);
-    cd->setInputGeometryB(triangleMesh2);
-    cd->update();
-
-    // Debug geometry to visualize collision data
-    auto cdDebugObj = std::make_shared<CollisionDataDebugObject>();
-    cdDebugObj->setInputCD(cd->getCollisionData());
-    cdDebugObj->setPrintContacts(true);
-    m_scene->addSceneObject(cdDebugObj);
-
-    // Light
-    auto light = std::make_shared<DirectionalLight>();
-    light->setFocalPoint(Vec3d(5.0, -8.0, -5.0));
-    light->setIntensity(1.0);
-    m_scene->addLight("Light", light);
-
-    std::cout << "================================================\n";
-    std::cout << "Key i/j/k/u/o move the triangle\n";
-    std::cout << "================================================\n\n";
-
-    connect<KeyEvent>(m_viewer->getKeyboardDevice(), &KeyboardDeviceClient::keyPress,
-        [&](KeyEvent* e)
-        {
-            const double s = 0.05;
-            if (e->m_key == 'i')
-            {
-                triangleMesh2->translate(Vec3d(0.0, 0.0, 1.0) * s);
-            }
-            else if (e->m_key == 'k')
-            {
-                triangleMesh2->translate(Vec3d(0.0, 0.0, -1.0) * s);
-            }
-            else if (e->m_key == 'j')
-            {
-                triangleMesh2->translate(Vec3d(-1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'l')
-            {
-                triangleMesh2->translate(Vec3d(1.0, 0.0, 0.0) * s);
-            }
-            else if (e->m_key == 'u')
-            {
-                triangleMesh2->translate(Vec3d(0.0, -1.0, 0.0) * s);
-            }
-            else if (e->m_key == 'o')
-            {
-                triangleMesh2->translate(Vec3d(0.0, 1.0, 0.0) * s);
-            }
-            triangleMesh2->postModified();
-            triangleMesh2->updatePostTransformData();
-            cd->update();
-            cdDebugObj->debugUpdate();
-        });
-    connect<Event>(m_driver, &SimulationManager::starting,
-        [&](Event*)
-        {
-            cdDebugObj->debugUpdate();
-        });
+    m_collisionMethod = std::make_shared<SurfaceMeshToSurfaceMeshCD>();
+    m_collisionMethod->setInputGeometryA(triangleMesh1);
+    m_collisionMethod->setInputGeometryB(triangleMesh2);
+    m_collisionMethod->update();
 
+    createScene();
     runFor(2.0);
 }
\ No newline at end of file
diff --git a/Source/RenderingVTK/VisualTesting/imstkRenderAnalyticalGeometryTest.cpp b/Source/RenderingVTK/VisualTesting/imstkRenderAnalyticalGeometryTest.cpp
index 6e98e34009af16ee8b3654b319d992164999584b..392029ebfe7aec17cb5fd933cefbf797a7e3adab 100644
--- a/Source/RenderingVTK/VisualTesting/imstkRenderAnalyticalGeometryTest.cpp
+++ b/Source/RenderingVTK/VisualTesting/imstkRenderAnalyticalGeometryTest.cpp
@@ -27,35 +27,35 @@
 #include "imstkPlane.h"
 #include "imstkSphere.h"
 
-TEST_F(RenderTest, createCapsule)
+TEST_F(RenderTest, Capsule)
 {
     geom = std::make_shared<Capsule>();
     createScene();
     runAllMaterials();
 }
 
-TEST_F(RenderTest, createCylinder)
+TEST_F(RenderTest, Cylinder)
 {
     geom = std::make_shared<Cylinder>();
     createScene();
     runAllMaterials();
 }
 
-TEST_F(RenderTest, createOrientedBox)
+TEST_F(RenderTest, OrientedBox)
 {
     geom = std::make_shared<OrientedBox>();
     createScene();
     runAllMaterials();
 }
 
-TEST_F(RenderTest, createPlane)
+TEST_F(RenderTest, Plane)
 {
     geom = std::make_shared<Plane>();
     createScene();
     runAllMaterials();
 }
 
-TEST_F(RenderTest, createSphere)
+TEST_F(RenderTest, Sphere)
 {
     geom = std::make_shared<Sphere>();
     createScene();
diff --git a/Source/RenderingVTK/VisualTesting/imstkRenderTest.h b/Source/RenderingVTK/VisualTesting/imstkRenderTest.h
index 7da7a92fbc989ef8c94a5fdbe9674bd66938a581..056d6ae2c89c53627dba08d89d8ce0c152a7859b 100644
--- a/Source/RenderingVTK/VisualTesting/imstkRenderTest.h
+++ b/Source/RenderingVTK/VisualTesting/imstkRenderTest.h
@@ -34,7 +34,7 @@ class VisualModel;
 
 using namespace imstk;
 
-class RenderTest : public VisualTestManager
+class RenderTest : public VisualTest
 {
 public:
     void runAllMaterials();
diff --git a/Source/RenderingVTK/VisualTesting/imstkRenderTetrahedralMeshTest.cpp b/Source/RenderingVTK/VisualTesting/imstkRenderTetrahedralMeshTest.cpp
index 69daff1777539451337ef69f25145bb8073394f2..bb41b629ad011ae086a9dc30d85c71fbd7b2a1f7 100644
--- a/Source/RenderingVTK/VisualTesting/imstkRenderTetrahedralMeshTest.cpp
+++ b/Source/RenderingVTK/VisualTesting/imstkRenderTetrahedralMeshTest.cpp
@@ -23,7 +23,7 @@
 #include "imstkTetrahedralMesh.h"
 #include "imstkVecDataArray.h"
 
-TEST_F(RenderTest, createTetrahedralMesh)
+TEST_F(RenderTest, TetrahedralMesh)
 {
     auto tetMesh = std::make_shared<TetrahedralMesh>();
     geom = tetMesh;
diff --git a/Source/Scene/VisualTesting/imstkPbdObjectCollisionTest.cpp b/Source/Scene/VisualTesting/imstkPbdObjectCollisionTest.cpp
index d4a953f68bdf34c1c7a7a4789fc13e1a386560e6..c8748b373bd2beaca3b9b0c1d6d20ba5ccfa43e5 100644
--- a/Source/Scene/VisualTesting/imstkPbdObjectCollisionTest.cpp
+++ b/Source/Scene/VisualTesting/imstkPbdObjectCollisionTest.cpp
@@ -377,7 +377,7 @@ makeLineThreadObj(const std::string& name,
     return tissueObj;
 }
 
-class PbdObjectCollisionTest : public VisualTestManager
+class PbdObjectCollisionTest : public VisualTest
 {
 public:
     void createScene()
diff --git a/Source/Testing/imstkTestingMain.cpp b/Source/Testing/imstkTestingMain.cpp
index b77eaa4f4442c68af12e8d10193db12079f8c012..b684f8501fd8faac38b6a0e3940ffb706e7ae67e 100644
--- a/Source/Testing/imstkTestingMain.cpp
+++ b/Source/Testing/imstkTestingMain.cpp
@@ -45,7 +45,6 @@ main(int argc, char** argv)
 
     auto& logger = imstk::Logger::getInstance();
     logger.addFileSink("test", "log");
-    logger.addStdoutSink();
 
     ::testing::InitGoogleTest(&argc, argv);
     GTEST_FLAG_SET(death_test_style, "threadsafe");
diff --git a/Source/Testing/imstkVisualTestingUtils.cpp b/Source/Testing/imstkVisualTestingUtils.cpp
index 60c56e988591f9c5f52b2d547b0b444c28a2c144..4df99ae315a5c59ea7c3061e4257f7427fa8c969 100644
--- a/Source/Testing/imstkVisualTestingUtils.cpp
+++ b/Source/Testing/imstkVisualTestingUtils.cpp
@@ -34,8 +34,12 @@
 using namespace imstk;
 
 void
-VisualTestManager::SetUp()
+VisualTest::SetUp()
 {
+    if (m_useStdOut)
+    {
+        Logger::getInstance().addStdoutSink();
+    }
     // Constructed early so user can subscribe calls to them
     m_driver       = std::make_shared<SimulationManager>();
     m_sceneManager = std::make_shared<SceneManager>();
@@ -43,7 +47,7 @@ VisualTestManager::SetUp()
 }
 
 void
-VisualTestManager::runFor(const double duration, const double fixedTimestep)
+VisualTest::runFor(const double duration, const double fixedTimestep)
 {
     m_duration = duration;
 
diff --git a/Source/Testing/imstkVisualTestingUtils.h b/Source/Testing/imstkVisualTestingUtils.h
index c5897da786faa66e35f10dc956c40681005dec49..951c9e1dfba60a9b60d987dc1e6c7a0e20827355 100644
--- a/Source/Testing/imstkVisualTestingUtils.h
+++ b/Source/Testing/imstkVisualTestingUtils.h
@@ -33,7 +33,7 @@ class VTKViewer;
 
 using namespace imstk;
 
-class VisualTestManager : public testing::Test
+class VisualTest : public testing::Test
 {
 public:
     void SetUp() override;
@@ -48,7 +48,8 @@ public:
 protected:
     double m_duration    = 2.0;   ///< Duration to run the test
     double m_dt          = 0.001; ///< Fixed timestep
-    bool   m_timerPaused = false;
+    bool   m_timerPaused = false; ///< Pauses the test timer
+    bool   m_useStdOut   = false; //< Enables std out in the logger, default off for testing
 
     std::shared_ptr<VTKViewer>         m_viewer       = nullptr;
     std::shared_ptr<SceneManager>      m_sceneManager = nullptr;