diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000000000000000000000000000000000..26b7b90f290470d564eeb8526ec60b76723feaf1
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "libs/googletest"]
+	path = libs/googletest
+	url = https://github.com/google/googletest.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 737b51021b3ccb1b6de8cd7e90a6179e11974922..8f3c5d712819558d928d08fd544e633461414d64 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,18 +1,38 @@
-## CMake file for the Q-Pong game.
-##
-project(QuantumPong)
-
+# CMake file for the QPong project.
+project(QPong)
 cmake_minimum_required(VERSION 3.2)
 
-## Use modern C++!
+
+# Options
+option(create_test "Build all tests." OFF)
+option(release_type "Set the type of the releas (Debug/Release)." Release)
+
+
+# Use modern C++!
 set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_BUILD_TYPE Release)
 
+
+## PkgConfig
 find_package(PkgConfig REQUIRED)
 
-message(" - Build type is set to ${CMAKE_BUILD_TYPE}")
 
-add_subdirectory(
-    src
-)
+# @todo Check versions of glib etc. librarys.
+# On Ubuntu 19.10 there are warnings which are not present in Ubuntu 18.04
+# set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
+
+
+# Add qpong lib for core qpong functionality
+add_subdirectory(qpong_core)
+include_directories(qpong_core)
+
+
+# Add dir with gtk qpong app
+add_subdirectory(gtk_qpong_app)
+
 
+# Add some unit tests
+# not many yet ^^
+if (create_test)
+    add_subdirectory(libs/googletest)
+    add_subdirectory(tests)
+endif()
diff --git a/README.md b/README.md
index 109ab413322fe1d94adcb5c423a8d47dd850aabb..44b8087c6c5e910c074e8287dea7cb8a002208aa 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,12 @@ make
 
 ````
 
+## TODOS
+   - ImageBuffer in die Klasse Particle ziehen,
+      - Methoden bereitstellen zum Abrufen der ImageBuffer
+      - ParticleImage muss das Particle Objekt kennen, um die ImageBuffer abrufen zu können.
+   - Umbauen der Klasse Particle zu einer Klasse Simulation Environemnt
+
 ## Erweiterungsideen
   - Konfiguration über die GUI, evt. mit speichern
   - Spalt & Interferenz
diff --git a/src/CMakeLists.txt b/gtk_qpong_app/CMakeLists.txt
similarity index 51%
rename from src/CMakeLists.txt
rename to gtk_qpong_app/CMakeLists.txt
index ea953791c8b9bd20f89a9f56260d76941af167a6..bafe30a2e44db8c7e4e56c7e308eeef8513ea929 100644
--- a/src/CMakeLists.txt
+++ b/gtk_qpong_app/CMakeLists.txt
@@ -1,18 +1,26 @@
-# library for the app should be GTK independent
-add_library(qpong
-    Particle.cpp
-    ImageBuffer.cpp
-    QPlayer.cpp
-    Profiler.cpp
-    Config.cpp
-)
+# Specific settings for macOS
+if(APPLE)
+    link_directories("/usr/local/lib")
+    message("ATTENTION: You probably have to export the PKG_CONFIG_PATH.")
+    message("For example: export PKG_CONFIG_PATH=\"/usr/local/lib:/usr/local/opt/zlib/lib/pkgconfig\"")
+endif()
+
+
+# Setup GTK configuration
+pkg_check_modules(GTKMM gtkmm-3.0)
+link_directories(${GTKMM_LIBRARY_DIRS})
+
+
+# get all GTKMM dependencies and configuration
+include_directories(${GTKMM_INCLUDE_DIRS})
+
+if(APPLE)
+    include_directories(/usr/local/include)
+endif()
 
-# @todo Check versions of glib etc. librarys.
-# On Ubuntu 19.10 there are warnings which are not present in Ubuntu 18.04
-set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
 
 # create the application
-add_executable(qpong.app 
+add_executable( qpong.app 
     main.cpp 
     QWindow.cpp
     QDrawingArea.cpp
@@ -23,15 +31,10 @@ add_executable(qpong.app
 # we do need some threads
 find_package(Threads)
 
-# get all GTKMM dependencies and configuration
-pkg_check_modules(GTKMM gtkmm-3.0)
-
-link_directories(${GTKMM_LIBRARY_DIRS})
-include_directories(${GTKMM_INCLUDE_DIRS})
 
 # link all necessary libs to the target
-target_link_libraries(qpong.app 
-    qpong
+target_link_libraries( qpong.app 
+    qpong_core
     ${CMAKE_THREAD_LIBS_INIT}
     ${GTKMM_LIBRARIES}
     fftw3
diff --git a/src/Common.cpp b/gtk_qpong_app/Common.cpp
similarity index 95%
rename from src/Common.cpp
rename to gtk_qpong_app/Common.cpp
index 06339680a6e5c4509e008ae462c8f0da71a23f58..cb507ffdfe84fbf62dcea030f605936074a71c97 100644
--- a/src/Common.cpp
+++ b/gtk_qpong_app/Common.cpp
@@ -1,4 +1,3 @@
-///
 /// @brief
 ///
 
diff --git a/src/Config.cpp b/gtk_qpong_app/Config.cpp
similarity index 100%
rename from src/Config.cpp
rename to gtk_qpong_app/Config.cpp
diff --git a/src/Config.hpp b/gtk_qpong_app/Config.hpp
similarity index 100%
rename from src/Config.hpp
rename to gtk_qpong_app/Config.hpp
diff --git a/src/ParticleImage.cpp b/gtk_qpong_app/ParticleImage.cpp
similarity index 97%
rename from src/ParticleImage.cpp
rename to gtk_qpong_app/ParticleImage.cpp
index fc6adaac0414bafc8b8e8789057db895ec2e32b6..e51aa727fca45ce3daf0f084f7981d0b0b976f23 100644
--- a/src/ParticleImage.cpp
+++ b/gtk_qpong_app/ParticleImage.cpp
@@ -4,9 +4,10 @@
 /// 
 
 #include "ParticleImage.hpp"
-#include "Profiler.hpp"
 #include "Common.hpp"
 
+using namespace QPong;
+
 constexpr int bytesPerPixel = 3;
 constexpr int bitsPerSample = 8;
 
diff --git a/src/ParticleImage.hpp b/gtk_qpong_app/ParticleImage.hpp
similarity index 90%
rename from src/ParticleImage.hpp
rename to gtk_qpong_app/ParticleImage.hpp
index 5e481856b7e4cee40e14f603cba07da3c7fe8f51..8d8ab97f11f891d77fe12bb83db31beafae7aed8 100644
--- a/src/ParticleImage.hpp
+++ b/gtk_qpong_app/ParticleImage.hpp
@@ -13,10 +13,11 @@
 #include "ImageBuffer.hpp"
 
 
+
 /// @brief  Wraps an one dimensional array.
 ///         Values can be accessed as in 2D.
 ///
-class ParticleImage : public ImageBuffer
+class ParticleImage : public QPong::ImageBuffer
 {
 public:
     ParticleImage();
diff --git a/src/QDrawingArea.cpp b/gtk_qpong_app/QDrawingArea.cpp
similarity index 99%
rename from src/QDrawingArea.cpp
rename to gtk_qpong_app/QDrawingArea.cpp
index 80f230391ed22412619b9af1170e38be4ab9fd8e..674092c4d316a1ddd81be3c4b28c1963e3ba7699 100644
--- a/src/QDrawingArea.cpp
+++ b/gtk_qpong_app/QDrawingArea.cpp
@@ -5,21 +5,25 @@
 
 #include "QDrawingArea.hpp"
 
+
 QDrawingArea::QDrawingArea()
 {
     m_dispatcher.connect(sigc::mem_fun(*this, &QDrawingArea::queue_draw));
 }
 
+
 void QDrawingArea::redraw()
 {
     m_dispatcher.emit();
 }
 
+
 void QDrawingArea::setPixbuf(Glib::RefPtr<Gdk::Pixbuf> pixbuf)
 {
     m_image = pixbuf;
 }
 
+
 bool QDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context> &cr)
 {
     cr->save();
diff --git a/src/QDrawingArea.hpp b/gtk_qpong_app/QDrawingArea.hpp
similarity index 100%
rename from src/QDrawingArea.hpp
rename to gtk_qpong_app/QDrawingArea.hpp
diff --git a/src/QWindow.cpp b/gtk_qpong_app/QWindow.cpp
similarity index 89%
rename from src/QWindow.cpp
rename to gtk_qpong_app/QWindow.cpp
index 861565904b64820ed45268b47f672703061bb318..ff42b83469a80e96a6b27a39d1f4084d3ba24bf0 100644
--- a/src/QWindow.cpp
+++ b/gtk_qpong_app/QWindow.cpp
@@ -4,8 +4,8 @@
 
 #include "QWindow.hpp"
 
-#include "Profiler.hpp"
 #include "Config.hpp"
+using namespace QPong;
 
 bool propagating = true;
 int propRate = 0;
@@ -28,16 +28,16 @@ void QWindow::simulation()
         propRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
             
         if (qPressed)
-            m_players[Player::One]->move(Direction::Up);
+            m_players[Player::Id::One]->move(Player::Direction::Up);
 
         if (aPressed)
-            m_players[Player::One]->move(Direction::Down);
+            m_players[Player::Id::One]->move(Player::Direction::Down);
 
         if (upPressed)
-            m_players[Player::Two]->move(Direction::Up);
+            m_players[Player::Id::Two]->move(Player::Direction::Up);
 
         if (downPressed)
-            m_players[Player::Two]->move(Direction::Down);
+            m_players[Player::Id::Two]->move(Player::Direction::Down);
 
         // Limit the speed of the simulation.
         auto dt = std::chrono::system_clock::now() - start;
@@ -59,7 +59,7 @@ void render(QWindow *w)
     {
         using namespace std::chrono_literals;
         auto start = std::chrono::system_clock::now();
-        std::this_thread::sleep_for(20ms);
+        std::this_thread::sleep_for(15ms);
         w->updateView();
         renderRate = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start).count();
     } while (true);
@@ -75,8 +75,8 @@ QWindow::QWindow()
 
     constexpr double playerOneStartX = -0.7;
     constexpr double playerTwoStartX = 0.7;
-    m_players.insert(std::make_pair<Player, std::shared_ptr<QPlayer>>(Player::One, std::make_shared<QPlayer>(Player::One, Position{-0.7, 0})));
-    m_players.insert(std::make_pair<Player, std::shared_ptr<QPlayer>>(Player::Two, std::make_shared<QPlayer>(Player::Two, Position{ 0.7, 0.4})));
+    m_players.insert(std::make_pair<Player::Id, std::shared_ptr<Player>>(Player::Id::One, std::make_shared<Player>(Player::Id::One, Player::Position{-0.7, 0})));
+    m_players.insert(std::make_pair<Player::Id, std::shared_ptr<Player>>(Player::Id::Two, std::make_shared<Player>(Player::Id::Two, Player::Position{ 0.7, 0.4})));
 
     m_momentum = new ParticleImage;
     m_position = new ParticleImage;
@@ -147,7 +147,7 @@ void QWindow::updateGui()
 
         ss = std::stringstream();
         ss << "Score Player 1: ";
-        auto score = m_players[Player::One]->getScore();
+        auto score = m_players[Player::Id::One]->getScore();
         ss << std::setprecision(2) << std::setw(7) << score << "%";
         if (score > 50.0)
         {
@@ -158,7 +158,7 @@ void QWindow::updateGui()
 
         ss = std::stringstream();
         ss << "Score Player 2: ";
-        score = m_players[Player::Two]->getScore();
+        score = m_players[Player::Id::Two]->getScore();
         ss << std::setprecision(2)  << std::setw(7) << score << "%";
         if (score > 50.0)
         {
diff --git a/src/QWindow.hpp b/gtk_qpong_app/QWindow.hpp
similarity index 93%
rename from src/QWindow.hpp
rename to gtk_qpong_app/QWindow.hpp
index d2f17b1765476df2a632cae59007cad0c6fcd3b4..b9a610d287b61eba61a38857d57448593b629257 100644
--- a/src/QWindow.hpp
+++ b/gtk_qpong_app/QWindow.hpp
@@ -72,13 +72,13 @@ private:
     QDrawingArea m_positionArea;
     QDrawingArea m_momentumArea;
 
-    Particle *m_particle;
+    QPong::Particle *m_particle;
     std::thread m_propagatingThread;
     ParticleImage *m_momentum;
     ParticleImage *m_position;
     ParticleImage *m_obstacle;
 
-    std::map<Player, std::shared_ptr<QPlayer>> m_players;
+    std::map<QPong::Player::Id, std::shared_ptr<QPong::Player>> m_players;
 };
 
 #endif
\ No newline at end of file
diff --git a/src/main.cpp b/gtk_qpong_app/main.cpp
similarity index 100%
rename from src/main.cpp
rename to gtk_qpong_app/main.cpp
diff --git a/src/qpong.config b/gtk_qpong_app/qpong.config
similarity index 100%
rename from src/qpong.config
rename to gtk_qpong_app/qpong.config
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/libs/googletest b/libs/googletest
index 8b4817e3df3746a20502a84580f661ac448821be..dcc92d0ab6c4ce022162a23566d44f673251eee4 160000
--- a/libs/googletest
+++ b/libs/googletest
@@ -1 +1 @@
-Subproject commit 8b4817e3df3746a20502a84580f661ac448821be
+Subproject commit dcc92d0ab6c4ce022162a23566d44f673251eee4
diff --git a/qpong_core/CMakeLists.txt b/qpong_core/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b6f2974fbc7fd21e6f24281e53c9e9b92c555f67
--- /dev/null
+++ b/qpong_core/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Add macOS specific include path.
+if(APPLE)
+    include_directories(/usr/local/include)
+endif()
+
+# Core QPong library
+add_library(qpong_core Particle.cpp ImageBuffer.cpp Player.cpp)
\ No newline at end of file
diff --git a/src/Common.hpp b/qpong_core/Common.hpp
similarity index 100%
rename from src/Common.hpp
rename to qpong_core/Common.hpp
diff --git a/src/ImageBuffer.cpp b/qpong_core/ImageBuffer.cpp
similarity index 88%
rename from src/ImageBuffer.cpp
rename to qpong_core/ImageBuffer.cpp
index 7ad83ea1537646fc5abcf05bc7826ea0d0ea3ef6..b4a524b9b65cb2edcd870e0871c34c8e87511aed 100644
--- a/src/ImageBuffer.cpp
+++ b/qpong_core/ImageBuffer.cpp
@@ -5,6 +5,8 @@
 #include "Common.hpp"
 #include "ImageBuffer.hpp"
 
+using namespace QPong;
+
 ImageBuffer::ImageBuffer()
 {
     m_potbuf = new double[QPong::arraySize];
@@ -28,11 +30,11 @@ const QColor ImageBuffer::getValue(unsigned index)
     
     QColor c {
         static_cast<float>(obs + r*r),          //< red
-        static_cast<float>(r*r + i*i + obs/2),  //< green
+        static_cast<float>(r*r + i*i + obs/1.5),  //< green
         static_cast<float>(i*i)                 //< blue
     };
 
-    constexpr double max = 0.83;
+    constexpr double max = 0.81;
     if (c.r > max)
     {
         c.r = max;
diff --git a/src/ImageBuffer.hpp b/qpong_core/ImageBuffer.hpp
similarity index 90%
rename from src/ImageBuffer.hpp
rename to qpong_core/ImageBuffer.hpp
index fcbb81ee504f60bedc83fed3a09b6fe20e5be845..d7b58e93e5c507e4a7a10e75731165230bf2894c 100644
--- a/src/ImageBuffer.hpp
+++ b/qpong_core/ImageBuffer.hpp
@@ -9,16 +9,18 @@
 
 #include <complex>
 
+namespace QPong
+{
+
 /// @brief Convinient conatiner to store a RGB value.
 ///        {r, g, b}
 struct QColor
 {
-    float r = 0;
-    float g = 0;
-    float b = 0;
+    float r = 0.0f;
+    float g = 0.0f;
+    float b = 0.0f;
 };
 
-
 /// @brief Class ImageBuffer
 ///
 class ImageBuffer
@@ -28,23 +30,22 @@ public:
     ///
     ImageBuffer();
 
-
     /// @brief Update the buffer at the given position.
     /// @param index Index of the value that should be changed.
     /// @param v The value as a complex number which will be interpreted as a color.
     /// @param pot Potential at position.
-    /// 
+    ///
     void updateAt(unsigned index, std::complex<double> v, double pot);
 
-
     /// @return Get color value from particle at array index.
     ///
     const QColor getValue(unsigned index);
 
-
 private:
     double *m_potbuf;
     std::complex<double> *m_complexBuffer;
 };
 
+} // namespace QPong
+
 #endif
diff --git a/src/Particle.cpp b/qpong_core/Particle.cpp
similarity index 83%
rename from src/Particle.cpp
rename to qpong_core/Particle.cpp
index eae2dfa90defd07c72e3ca5a298da6b9e2358c51..c639bfe2f0baab602cb00bd81ef011215a044854 100644
--- a/src/Particle.cpp
+++ b/qpong_core/Particle.cpp
@@ -11,9 +11,10 @@
 
 #include "Common.hpp"
 #include "Particle.hpp"
-#include "Profiler.hpp"
 #include "Config.hpp"
 
+using namespace QPong;
+
 
 const std::complex<double> Ci(0.0, 1.0);
 
@@ -69,7 +70,7 @@ void Particle::initMomentum()
 }
 
 
-Particle::Particle(ImageBuffer *momentum, ImageBuffer *position, std::map<Player, std::shared_ptr<QPlayer>> players)
+Particle::Particle(ImageBuffer *momentum, ImageBuffer *position, std::map<Player::Id, std::shared_ptr<Player>> players)
     : m_bufMomentumRepresentation{momentum}
     , m_bufPositionRepresentation{position}
     , m_ready{false}
@@ -101,31 +102,15 @@ bool Particle::notReady()
 
 double Particle::removeParticle(int index, double cx)
 {
-    double e = cos(cx) * cos(cx);
-    double normPre = sqr(std::real(m_psi[index])) + sqr(std::real(m_psi[index]));
+    double normPre  = sqr(std::real(m_psi[index])) + sqr(std::imag(m_psi[index]));
+    double e =  sqr(cos(cx));
     m_psi[index] *= e;
-    double dif = normPre - (sqr(std::real(m_psi[index])) + sqr(std::real(m_psi[index])));
+    double dif = normPre - (sqr(std::real(m_psi[index])) + sqr(std::imag(m_psi[index])));
     return dif;
 }
 
 
-const double pxAt(int ix)
-{
-    if (ix > Config::getArrayWidth() / 2)
-        ix -= Config::getArrayWidth();
-    return ix * M_PI * Config::getHbar();
-}
-
-
-const double pyAt(int iy)
-{
-    if (iy > Config::getArrayHeight() / 2)
-        iy -= Config::getArrayHeight();
-    return iy * M_PI * Config::getHbar();
-}
-
-
-const double batPotential(double x, double y, Position pos)
+const double batPotential(double x, double y, Player::Position pos)
 {
     y -= pos.y;
     double E = 0.0;
@@ -154,8 +139,8 @@ const double batPotential(double x, double y, Position pos)
 constexpr double dt = 0.15;
 void Particle::manipulateParticleInPosition(int indexFrom, int indexTo)
 {
-    auto pOneX = m_players[Player::One]->getPosition().x;
-    auto pTwoX = m_players[Player::Two]->getPosition().x;
+    auto pOneX = m_players[Player::Id::One]->getPosition().x;
+    auto pTwoX = m_players[Player::Id::Two]->getPosition().x;
     float sumScorePlayerOne = 0.0;
     float sumScorePlayerTwo = 0.0;
 
@@ -166,41 +151,62 @@ void Particle::manipulateParticleInPosition(int indexFrom, int indexTo)
         if (x < pOneX) //< expects p1.x < 0
         {
             double cx = -pOneX + x;
-            cx = cx * (M_PI / 2) / (1.0 + pOneX);
+            cx = cx * (M_PI / 2.0) / (1.0 + pOneX);
             double dif = removeParticle(index, cx);
             sumScorePlayerTwo += dif;
         }
         if (x > pTwoX) //< expects p2.x > 0
         {
             double cx = x - pTwoX;
-            cx = cx * (M_PI / 2) / (1.0 - pTwoX);
+            cx = cx * (M_PI / 2.0) / (1.0 - pTwoX);
             double dif = removeParticle(index, cx);
             sumScorePlayerOne += dif;
         }
-        double playerOneBat = batPotential(x, y, m_players[Player::One]->getPosition());
-        double playerTwoBat = batPotential(x, y, m_players[Player::Two]->getPosition());
+        double playerOneBat = batPotential(x, y, m_players[Player::Id::One]->getPosition());
+        double playerTwoBat = batPotential(x, y, m_players[Player::Id::Two]->getPosition());
         double horizontalBorders = sqr(y) * sqr(y) * sqr(y) * sqr(y) * 0.01;
-        std::complex<double> tmp = m_psi[index] * exp(-Ci * dt / Config::getHbar() * (playerOneBat + playerTwoBat + horizontalBorders));
-        m_psi[index] = tmp;
-        m_bufPositionRepresentation->updateAt(index, tmp * 125.0, (playerOneBat + playerTwoBat + horizontalBorders) * 150);
+        auto potentialSum = playerOneBat + playerTwoBat + horizontalBorders;
+        auto tmpPsi = m_psi[index] * exp(-Ci * dt / hbar * potentialSum);
+        m_psi[index] = tmpPsi;
+        m_bufPositionRepresentation->updateAt(index, tmpPsi * 125.0, potentialSum * 150);
     }
-    m_players[Player::One]->addScore(sumScorePlayerOne);
-    m_players[Player::Two]->addScore(sumScorePlayerTwo);
+    m_players[Player::Id::One]->addScore(sumScorePlayerOne);
+    m_players[Player::Id::Two]->addScore(sumScorePlayerTwo);
 }
 
 
 double flattenMomentum(double x, double y)
 {
     double distanceToCenter = sqr(x) + sqr(y);
-    double offset = Config::getFlattenMomentumCutOff();
-    if (distanceToCenter < offset)
+    constexpr double offset = 0.012;
+    if (distanceToCenter > offset)
     {
-        return 1.0;
+        return 1.0 / (1.0 + (distanceToCenter * 2.5));
     }
     else
     {
-        return 1.0 / (1.0 + (distanceToCenter * Config::getFlattenMomentumFallOff()));
+        return 1.0;
+    }
+}
+
+
+const double pxAt(int ix)
+{
+    if (ix > QPong::arrayWidth / 2)
+    {
+        ix -= QPong::arrayWidth;
+    }
+    return ix * M_PI * hbar;
+}
+
+
+const double pyAt(int iy)
+{
+    if (iy > QPong::arrayHeight / 2)
+    {
+        iy -= QPong::arrayHeight;
     }
+    return iy * M_PI * hbar;
 }
 
 
@@ -213,7 +219,9 @@ void Particle::moveStep(int indexFrom, int indexTo)
         constexpr double m = 1.0;   
         double N = 1.0 / Config::getArraySize();
         double E = (sqr(px) + sqr(py)) / (2.0 * m);
-        m_psi[i] *= exp(-Ci * dt / Config::getHbar() * E) * N * flattenMomentum(px, py);
+        auto f = flattenMomentum(px, py);
+        m_psi[i] *= exp(-Ci * dt / hbar * E) * N * f;
+        // m_psi[i] = flattenMomentum(px, py) * 0.00001;
     }
 }
 
diff --git a/src/Particle.hpp b/qpong_core/Particle.hpp
similarity index 90%
rename from src/Particle.hpp
rename to qpong_core/Particle.hpp
index 4f67371c919d0f6a5a71686b22d636a6b4ee292e..0477612d625d4c2a94cd8a10cc3ba44943efb554 100644
--- a/src/Particle.hpp
+++ b/qpong_core/Particle.hpp
@@ -1,7 +1,6 @@
 ///
 /// @file       Particle.hpp
 /// @author     Armin Co
-///
 /// @brief      Particle class header.
 ///
 
@@ -16,8 +15,9 @@
 #include <fftw3.h>
 
 #include "ImageBuffer.hpp"
-#include "QPlayer.hpp"
+#include "Player.hpp"
 
+namespace QPong {
 
 class Particle
 {
@@ -25,7 +25,7 @@ public:
 
     /// @brief Contructor
     ///
-    Particle(ImageBuffer *momentum, ImageBuffer *position, std::map<Player, std::shared_ptr<QPlayer>> players);
+    Particle(ImageBuffer *momentum, ImageBuffer *position, std::map<Player::Id, std::shared_ptr<Player>> players);
     
     
     /// @brief Destructor
@@ -50,17 +50,6 @@ public:
 
 
 private:
-    std::complex<double> *m_psi;
-    fftw_plan m_planForward;
-    fftw_plan m_planBackward;
-    bool m_ready;
-
-    std::map<Player, std::shared_ptr<QPlayer>> m_players;
-
-    ImageBuffer *m_bufPositionRepresentation;
-    ImageBuffer *m_bufMomentumRepresentation;
-
-
     /// @brief Update the array at the ArrayCanvas
     ///
     void updateMomentumImage();
@@ -83,7 +72,22 @@ private:
     double removeParticle(int index, double cx);
 
 
+    std::complex<double> *m_psi;
+    fftw_plan m_planForward;
+    fftw_plan m_planBackward;
+    bool m_ready;
+
+    std::map<Player::Id, std::shared_ptr<Player>> m_players;
+
+    ImageBuffer *m_bufPositionRepresentation;
+    ImageBuffer *m_bufMomentumRepresentation;
+
+
+
+
     Particle() = delete;
 };
 
+} // namespace QPong
+
 #endif
\ No newline at end of file
diff --git a/src/QPlayer.cpp b/qpong_core/Player.cpp
similarity index 78%
rename from src/QPlayer.cpp
rename to qpong_core/Player.cpp
index 925be69d952a127d3fdd030e3d8edb7290db31e9..31db21340b65b86981484c1555e600563c7b524e 100644
--- a/src/QPlayer.cpp
+++ b/qpong_core/Player.cpp
@@ -3,23 +3,24 @@
 /// @author     Armin Co
 ///
 
-#include "QPlayer.hpp"
 
 #include <mutex>
+#include "Player.hpp"
+
+using namespace QPong;
 
 constexpr double speedStepSize = 0.0005;
 
 
-QPlayer::QPlayer(Player pl, Position pos)
+Player::Player(Player::Id pl, Player::Position pos)
     : m_id {pl}
     , m_x {pos.x}
     , m_y {pos.y}
 {
-
 }
 
 
-void QPlayer::update(double dt)
+void Player::update(double dt)
 {
     constexpr double negativeAccelScale = 1.5;
     m_y += (m_vy * dt * 4);
@@ -49,7 +50,7 @@ void QPlayer::update(double dt)
 }
 
 
-void QPlayer::move(Direction direction)
+void Player::move(Direction direction)
 {
     constexpr double addSpped = 3;
     switch (direction)
@@ -74,28 +75,27 @@ void QPlayer::move(Direction direction)
 }
 
 
-float QPlayer::getScore()
+float Player::getScore()
 {
     return m_score * 100;
 }
 
 
-std::mutex mtx;
-
-void QPlayer::addScore(float score)
+std::mutex scoreMtx;
+void Player::addScore(float score)
 {
-    std::lock_guard<std::mutex> lockScore(mtx);
+    std::lock_guard<std::mutex> lockScore(scoreMtx);
     m_score += score;
 }
 
 
-Position QPlayer::getPosition()
+Player::Position Player::getPosition()
 {
     return {m_x, m_y};
 }
 
 
-void QPlayer::reset()
+void Player::reset()
 {
     m_score = 0;
 }
\ No newline at end of file
diff --git a/src/QPlayer.hpp b/qpong_core/Player.hpp
similarity index 55%
rename from src/QPlayer.hpp
rename to qpong_core/Player.hpp
index 22f42ea3ee1d04c4a63cc1540f28b3d25f5b4957..7154bc9ae2705929b17696a2638a33f2cd264ad0 100644
--- a/src/QPlayer.hpp
+++ b/qpong_core/Player.hpp
@@ -8,42 +8,44 @@
 #ifndef QPONG_QPLAYER_HPP
 #define QPONG_QPLAYER_HPP
 
-/// @brief Available players
-///
-enum class Player
-{
-    One,
-    Two
-};
+namespace QPong {
 
-/// @brief The bat can be moved up and down.
-///
-enum class Direction
+/// @brief Class wraps all values of one Player.
+/// 
+class Player
 {
-    Up,
-    Down
-};
+public:
+    enum class Id
+    {
+        One,
+        Two
+    };
 
-struct Position
-{
-    double x;
-    double y;
-};
 
-class QPlayer
-{
-public:
-    QPlayer(Player pl, Position pos);
+    struct Position
+    {
+        double x;
+        double y;
+    };
+
+
+    enum class Direction
+    {
+        Up,
+        Down
+    };
+
+
+    Player(Id pl, Position pos);
     void update(double dt);
     void move(Direction d);
-    float getScore();
     void addScore(float score);
     void reset();
-
+    float getScore();
     Position getPosition();
 
 private:
-    Player m_id;
+    Id m_id;
     double m_x;
     double m_y;
     double m_vx = 0;
@@ -51,4 +53,6 @@ private:
     double m_score = 0;
 };
 
+} // namespace QPong
+
 #endif
\ No newline at end of file
diff --git a/src/Profiler.cpp b/src/Profiler.cpp
deleted file mode 100644
index e3346012892de08bee0593dc5397ebdac6162e52..0000000000000000000000000000000000000000
--- a/src/Profiler.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-///
-/// @file       Profiler.cpp
-/// @author     Armin Co
-///
-/// @brief
-
-#include "Profiler.hpp"
-
-Profiler::Profiler(const char* name)
-    : m_name {name}
-    , m_stopped {false}
-    , m_verbose {Verbose::False}
-{
-    m_startTimepoint = std::chrono::high_resolution_clock::now();
-}
-
-Profiler::~Profiler()
-{
-    if (!m_stopped)
-    {
-        stop();
-    }
-}
-
-long Profiler::stop()
-{
-    auto endTimepoint = std::chrono::high_resolution_clock::now();
-    m_stopped = true;
-    long mus = std::chrono::duration_cast<std::chrono::nanoseconds>(endTimepoint - m_startTimepoint).count();
-    
-    if (m_verbose == Verbose::True)
-    {
-        std::cout << m_name << ": " << mus / 1000.0 / 1000.0<< "ms" << std::endl;
-    }
-
-    return mus;
-}
\ No newline at end of file
diff --git a/src/Profiler.hpp b/src/Profiler.hpp
deleted file mode 100644
index 24a39ee26deb9b2e2756b87b6c5b9d79fb21eb69..0000000000000000000000000000000000000000
--- a/src/Profiler.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-///
-/// @file       Profiler.hpp
-/// @author     Armin Co
-///
-/// @brief      Class to do some basic timing and profiling.
-///
-
-#ifndef QPONG_PROFILER_HPP
-#define QPONG_PROFILER_HPP
-
-#include <chrono>
-#include <iostream>
-
-enum class Verbose
-{
-    True,
-    False
-};
-
-class Profiler
-{
-
-public:
-    Profiler(const char* name);
-    ~Profiler();
-
-    long stop();
-
-private:
-    const char* m_name;
-    Verbose m_verbose;
-    std::chrono::time_point<std::chrono::system_clock> m_startTimepoint;
-    bool m_stopped;
-
-};
-
-#endif
\ No newline at end of file
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0f98b3350c88a659ba0c241e28dc1b5d184275bd
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,23 @@
+
+enable_testing()
+
+include_directories(
+    ${gtest_SOURCE_DIR}/include 
+    ${gtest_SOURCE_DIR}
+)
+
+add_executable(
+    runUnitTests
+    test_qpong.cpp
+)
+
+target_link_libraries(
+    runUnitTests
+    gtest
+    gtest_main
+)
+
+target_link_libraries(
+    runUnitTests
+    qpong_core
+)
diff --git a/tests/test_qpong.cpp b/tests/test_qpong.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..203e84f6c4600c2f707e4ae16ec91816512cccc8
--- /dev/null
+++ b/tests/test_qpong.cpp
@@ -0,0 +1,65 @@
+#include <iostream>
+#include "gtest/gtest.h"
+
+#include "ImageBuffer.hpp"
+
+
+/// @brief Creating a test fixture frequently used objects for tests
+///
+class QPongLib : public testing::Test
+{
+    protected:
+    ImageBuffer *momentumImage;
+    ImageBuffer *positionImage;
+    // members
+
+    // called before any test
+    void SetUp() override
+    {
+
+    }
+
+    virtual void TearDown()
+    {
+
+    }
+
+};
+
+/// @brief A simple function to test
+///
+int addInts(int a, int b)
+{
+    return a + b;
+}
+
+
+TEST(ImageBuffer, getValue)
+{
+    const ImageBuffer imbf;
+    const ImageBuffer imbff;
+    const ImageBuffer imbfff;
+    
+}
+
+
+TEST(addInts, positiveValues)
+{
+    int a {1};
+    int b {3};
+
+    ASSERT_EQ(addInts(a, b), 4);
+}
+
+TEST(addInts, shouldBreak)
+{
+    EXPECT_NE(3+1, 0) << "Yes yes, because it is just a test!";
+}
+
+TEST(addInts, negativeValues)
+{
+    ASSERT_EQ(-3 + -5, -8);
+}
+
+/// @todo Example for mocks and an explanation what they are.
+///
\ No newline at end of file