diff --git a/unit_tests/operator/Test_ErfImpl.cpp b/unit_tests/operator/Test_ErfImpl.cpp
index 2826b5b57d431cf8296a9869f88f7d642c59c963..c2fdd1c8606804e4a9f63051fa66667ae374fb9d 100644
--- a/unit_tests/operator/Test_ErfImpl.cpp
+++ b/unit_tests/operator/Test_ErfImpl.cpp
@@ -9,14 +9,16 @@
  *
  ********************************************************************************/
 
+#include <memory>
+
 #include <catch2/catch_test_macros.hpp>
 
+#include "aidge/backend/cpu/operator/ErfImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/Erf.hpp"
-
-#include "aidge/backend/cpu.hpp"
-
-#include <memory>
+#include "aidge/utils/ArrayHelpers.hpp"
+#include "aidge/utils/TensorUtils.hpp"
 
 
 using namespace Aidge;
@@ -27,23 +29,18 @@ TEST_CASE("[cpu/operator] Erf(forward)") {
             {0.41384590, 0.43120754, 0.93762982, 0.31049860, 0.77547199, 0.09514862,
               0.16145366, 0.42776686, 0.43487436, 0.41170865}
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array1D<float,10> {
+        Tensor expectedOutput = Array1D<float,10> {
                 {0.44163144, 0.45801866, 0.81516320, 0.33941913, 0.72722000, 0.10704061,
               0.18061027, 0.45479023, 0.46144873, 0.43959764}
-        });
+        };
 
-        std::shared_ptr<Node> myErf = Erf();
-        auto op = std::static_pointer_cast<OperatorTensor>(myErf -> getOperator());
+        auto op = std::make_shared<Erf_Op>();
         op->associateInput(0,input0);
         op->setDataType(DataType::Float32);
         op->setBackend("cpu");
-        myErf->forward();
+        op->forward();
 
-        float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
-        float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
-        for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
-            REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
-        }
+        REQUIRE(approxEq<float>(*(op->getOutput(0)), expectedOutput, 1e-5f, 1e-8f));
     }
 
     SECTION("3D Tensor") {
@@ -59,7 +56,7 @@ TEST_CASE("[cpu/operator] Erf(forward)") {
                 }
             }
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array3D<float,2,2,3> {
+        Tensor expectedOutput = Array3D<float,2,2,3> {
             {
                 {
                     {0.83003384, 0.77721894, 0.72857803},
@@ -70,19 +67,14 @@ TEST_CASE("[cpu/operator] Erf(forward)") {
                     {0.81564975, 0.83322692, 0.37109339}
                 }
             }
-        });
+        };
 
-        std::shared_ptr<Node> myErf = Erf();
-        auto op = std::static_pointer_cast<OperatorTensor>(myErf -> getOperator());
+        auto op = std::make_shared<Erf_Op>();
         op->associateInput(0,input0);
         op->setDataType(DataType::Float32);
         op->setBackend("cpu");
-        myErf->forward();
+        op->forward();
 
-        float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
-        float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
-        for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
-            REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
-        }
+        REQUIRE(approxEq<float>(*(op->getOutput(0)), expectedOutput, 1e-5f, 1e-8f));
     }
 }
\ No newline at end of file
diff --git a/unit_tests/operator/Test_ExpandImpl.cpp b/unit_tests/operator/Test_ExpandImpl.cpp
index 3fcb5e4460388712abb99dc4aa2f1fd0f274d841..878c608110eabb824d8a6c0d1ceb0853b3c1449d 100644
--- a/unit_tests/operator/Test_ExpandImpl.cpp
+++ b/unit_tests/operator/Test_ExpandImpl.cpp
@@ -9,21 +9,16 @@
  *
  ********************************************************************************/
 
-#include <aidge/data/Data.hpp>
-#include <aidge/operator/OperatorTensor.hpp>
-#include <aidge/utils/ArrayHelpers.hpp>
-#include <aidge/utils/TensorUtils.hpp>
-#include <aidge/utils/Types.h>
-#include <catch2/catch_test_macros.hpp>
-#include <cstdint>
-#include <cstdlib>
 #include <memory>
 
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/ExpandImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
-#include "aidge/filler/Filler.hpp"
 #include "aidge/operator/Expand.hpp"
-
-#include "aidge/backend/cpu.hpp"
+#include "aidge/utils/ArrayHelpers.hpp"
 
 using std::shared_ptr;
 
@@ -31,8 +26,7 @@ using namespace Aidge;
 
 void setupTestExpand(shared_ptr<Tensor> inputData,
                      shared_ptr<Tensor> inputShape,
-                     shared_ptr<OperatorTensor> &op,
-                     shared_ptr<Tensor> &expectedOutput) {
+                     shared_ptr<Expand_Op> &op) {
 
     op->getOutput(0)->setDataType(inputData->dataType());
 
@@ -41,72 +35,68 @@ void setupTestExpand(shared_ptr<Tensor> inputData,
 
     inputShape->setBackend("cpu");
     op->associateInput(1, inputShape);
-
-    expectedOutput->setBackend("cpu");
-    expectedOutput->setDataType(DataType::Int32);
 }
 
 TEST_CASE("[cpu/operator] Expand(forward)", "[Expand][CPU]") {
-    auto node = Expand();
-    auto op = std::static_pointer_cast<OperatorTensor>(node->getOperator());
+    std::shared_ptr<Expand_Op> op = std::make_shared<Expand_Op>();
     op->setBackend("cpu");
 
     SECTION("Expand shape is bigger than inputData") {
         auto inputData = std::make_shared<Tensor>(Array1D<int, 2>({1, 3}));
         auto inputShape =
             std::make_shared<Tensor>(Array1D<std::int64_t, 4>({1, 3, 4, 2}));
-        auto expectedOutput = std::make_shared<Tensor>(
-            Array4D<int, 1, 3, 4, 2>({{{{{1, 3}, {1, 3}, {1, 3}, {1, 3}},
+        Tensor expectedOutput =
+            Array4D<cpptype_t<DataType::Int32>, 1, 3, 4, 2>({{{{{1, 3}, {1, 3}, {1, 3}, {1, 3}},
                                         {{1, 3}, {1, 3}, {1, 3}, {1, 3}},
-                                        {{1, 3}, {1, 3}, {1, 3}, {1, 3}}}}}));
-        setupTestExpand(inputData, inputShape, op, expectedOutput);
+                                        {{1, 3}, {1, 3}, {1, 3}, {1, 3}}}}});
+        setupTestExpand(inputData, inputShape, op);
 
         // forwardDims has already been tested in core
         CHECK(op->forwardDims(true));
         REQUIRE_NOTHROW(op->forward());
-        CHECK(approxEq<int>(*expectedOutput, *op->getOutput(0)));
+        REQUIRE(expectedOutput == *op->getOutput(0));
     }
     SECTION("Expand shape has less dimensions than inputData") {
         auto inputData = std::make_shared<Tensor>(
             Array3D<int, 2, 1, 3>({{{2, 1, 3}, {2, 1, 3}}}));
         auto inputShape =
             std::make_shared<Tensor>(Array1D<std::int64_t, 2>({2, 3}));
-        auto expectedOutput = std::make_shared<Tensor>(Array3D<int, 2, 2, 3>(
-            {{{{2, 1, 3}, {2, 1, 3}}, {{2, 1, 3}, {2, 1, 3}}}}));
-        setupTestExpand(inputData, inputShape, op, expectedOutput);
+        Tensor expectedOutput = Array3D<cpptype_t<DataType::Int32>, 2, 2, 3>(
+            {{{{2, 1, 3}, {2, 1, 3}}, {{2, 1, 3}, {2, 1, 3}}}});
+        setupTestExpand(inputData, inputShape, op);
 
         // forwardDims has already been tested in core
         CHECK(op->forwardDims(true));
         REQUIRE_NOTHROW(op->forward());
-        CHECK(approxEq<int>(*expectedOutput, *op->getOutput(0)));
+        REQUIRE(expectedOutput == *op->getOutput(0));
     }
     SECTION("Expand shape = {1} leads to input equal to output.") {
         auto inputData = std::make_shared<Tensor>(
             Array4D<int, 2, 1, 3, 1>({{{2, 1, 3}, {2, 1, 3}}}));
         auto inputShape =
             std::make_shared<Tensor>(Array1D<std::int64_t, 1>({1}));
-        auto expectedOutput = std::make_shared<Tensor>(
-            Array4D<int, 2, 1, 3, 1>({{{2, 1, 3}, {2, 1, 3}}}));
-        setupTestExpand(inputData, inputShape, op, expectedOutput);
+        Tensor expectedOutput =
+            Array4D<cpptype_t<DataType::Int32>, 2, 1, 3, 1>({{{2, 1, 3}, {2, 1, 3}}});
+        setupTestExpand(inputData, inputShape, op);
 
         // forwardDims has already been tested in core
         CHECK(op->forwardDims(true));
         REQUIRE_NOTHROW(op->forward());
-        CHECK(approxEq<int>(*expectedOutput, *op->getOutput(0)));
+        REQUIRE(expectedOutput == *op->getOutput(0));
     }
     SECTION("The only common dimension is the last one & its equal to 1") {
         auto inputData = std::make_shared<Tensor>(
             Array4D<int, 1, 1, 3, 1>({{{{2, 1, 3}}}}));
         auto inputShape =
             std::make_shared<Tensor>(Array1D<std::int64_t, 3>({2, 1, 1}));
-        auto expectedOutput = std::make_shared<Tensor>(
-            Array4D<int, 1, 2, 3, 1>({{{{2, 1, 3}, {2, 1, 3}}}}));
-        setupTestExpand(inputData, inputShape, op, expectedOutput);
+        Tensor expectedOutput =
+            Array4D<cpptype_t<DataType::Int32>, 1, 2, 3, 1>({{{{2, 1, 3}, {2, 1, 3}}}});
+        setupTestExpand(inputData, inputShape, op);
 
         // forwardDims has already been tested in core
         CHECK(op->forwardDims(true));
         REQUIRE_NOTHROW(op->forward());
-        CHECK(approxEq<int>(*expectedOutput, *op->getOutput(0)));
+        REQUIRE(expectedOutput == *op->getOutput(0));
     }
     SECTION("N-Dim to N-Dim") {}
     auto inputData = std::shared_ptr<Tensor>();
diff --git a/unit_tests/operator/Test_FCImpl.cpp b/unit_tests/operator/Test_FCImpl.cpp
index b2566f26d984fb1d89052745ec35870c6b935d48..8ac0afc33152f4ae110b1c3ef0b4e88f37b00e99 100644
--- a/unit_tests/operator/Test_FCImpl.cpp
+++ b/unit_tests/operator/Test_FCImpl.cpp
@@ -9,13 +9,16 @@
  *
  ********************************************************************************/
 
-#include <catch2/catch_test_macros.hpp>
 #include <memory>
 
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/FCImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/FC.hpp"
-
-#include "aidge/backend/cpu.hpp"
+#include "aidge/utils/ArrayHelpers.hpp"
 
 using namespace Aidge;
 
@@ -42,11 +45,13 @@ TEST_CASE("[cpu/oeprator] FC(forward)", "[FC][CPU]") {
               9,  10, 11, 12, 13, 14, 15, 1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12,
               13, 14, 15, 1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15}}});
     std::shared_ptr<Tensor> myBias = std::make_shared<Tensor>(Array1D<int, 5>{{1, 2, 3, 4, 5}});
-    std::shared_ptr<Tensor> myOutput = std::make_shared<Tensor>(Array2D<int, 2, 5>{
-            {{23601, 23602, 23603, 23604, 23605}, {68601, 68602, 68603, 68604, 68605}}});
+    Tensor myOutput = Array2D<int, 2, 5>{
+            {{23601, 23602, 23603, 23604, 23605}, {68601, 68602, 68603, 68604, 68605}}};
 
     std::shared_ptr<Node> myFC = FC(75, 5, false, "myfc");
-    auto op = std::static_pointer_cast<OperatorTensor>(myFC -> getOperator());
+    auto op = std::static_pointer_cast<FC_Op>(myFC -> getOperator());
+    op -> setDataType(DataType::Int32);
+    op -> setBackend("cpu");
     op -> associateInput(1, myWeights);
     op -> associateInput(2, myBias);
 
@@ -62,10 +67,8 @@ TEST_CASE("[cpu/oeprator] FC(forward)", "[FC][CPU]") {
                   120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
                   135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149}}});
         op->associateInput(0, myInput);
-        op -> setDataType(DataType::Int32);
-        op -> setBackend("cpu");
         myFC->forward();
-        REQUIRE(*(op->getOutput(0)) == *myOutput);
+        REQUIRE(*(op->getOutput(0)) == myOutput);
     }
     SECTION("4D input") {
         std::shared_ptr<Tensor> myInput =
@@ -100,10 +103,8 @@ TEST_CASE("[cpu/oeprator] FC(forward)", "[FC][CPU]") {
                                                                      {140, 141, 142, 143, 144},
                                                                      {145, 146, 147, 148, 149}}}}});
         op->associateInput(0, myInput);
-        op -> setDataType(DataType::Int32);
-        op -> setBackend("cpu");
         myFC->forward();
-        REQUIRE(*(op->getOutput(0)) == *myOutput);
+        REQUIRE(*(op->getOutput(0)) == myOutput);
     }
 
     // std::cout << static_cast<Tensor>((*myFC->getOperator())["weight"])[0][0][0][0] << std::endl;
diff --git a/unit_tests/operator/Test_FoldImpl.cpp b/unit_tests/operator/Test_FoldImpl.cpp
index 6832f5a42d796d9261495794e0758ce1b6df0346..184b9e9acfe2cd5e86f74d304e37ba2aeacc7cf5 100644
--- a/unit_tests/operator/Test_FoldImpl.cpp
+++ b/unit_tests/operator/Test_FoldImpl.cpp
@@ -13,6 +13,7 @@
 #include <cstdlib>
 #include <memory>
 
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/graph/GraphView.hpp"
 #include "aidge/scheduler/SequentialScheduler.hpp"
@@ -21,8 +22,6 @@
 #include "aidge/operator/MatMul.hpp"
 #include "aidge/operator/Reshape.hpp"
 
-#include "aidge/backend/cpu.hpp"
-
 using namespace Aidge;
 
 TEST_CASE("[cpu/operator] Fold(forward)", "[Fold][CPU]") {
diff --git a/unit_tests/operator/Test_LeakyReLUImpl.cpp b/unit_tests/operator/Test_LeakyReLUImpl.cpp
index 85dd9f99ee425216f8495e7813b35ce69be9c806..b60b8bb3e50a33eb339f66905c81d6824e28a835 100644
--- a/unit_tests/operator/Test_LeakyReLUImpl.cpp
+++ b/unit_tests/operator/Test_LeakyReLUImpl.cpp
@@ -9,13 +9,16 @@
  *
  ********************************************************************************/
 
+#include <memory>
+
 #include <catch2/catch_test_macros.hpp>
 
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/LeakyReLUImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/LeakyReLU.hpp"
 
-#include "aidge/backend/cpu.hpp"
-
 using namespace Aidge;
 
 TEST_CASE("[cpu/operator] LeakyReLU(forward)", "[LeakyReLU][CPU]") {
diff --git a/unit_tests/operator/Test_MaxPoolingImpl.cpp b/unit_tests/operator/Test_MaxPoolingImpl.cpp
index af04ede4e33c32ce785804e2484b6ba9ac5edc36..de02df2b73bc461bbd76b089cd555d7c82bd173e 100644
--- a/unit_tests/operator/Test_MaxPoolingImpl.cpp
+++ b/unit_tests/operator/Test_MaxPoolingImpl.cpp
@@ -9,15 +9,17 @@
  *
  ********************************************************************************/
 
-#include <catch2/catch_test_macros.hpp>
+#include <array>
 #include <memory>
-#include <cstdlib>
 
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/MaxPoolingImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/MaxPooling.hpp"
 
-#include "aidge/backend/cpu.hpp"
-
 using namespace Aidge;
 
 
@@ -53,10 +55,9 @@ TEST_CASE("[cpu/operator] MaxPooling(forward)", "[MaxPooling][CPU]") {
         }
     });
     SECTION("Stride") {
-        std::shared_ptr<Node> myMaxPool = MaxPooling({2,2}, "mycdw", {2,2});
-        auto op = std::static_pointer_cast<OperatorTensor>(myMaxPool -> getOperator());
+        std::shared_ptr<MaxPooling_Op<2>> op = std::make_shared<MaxPooling_Op<2>>(std::array<std::size_t, 2>({2,2}), std::array<std::size_t, 2>({2,2}));
 
-        std::shared_ptr<Tensor> myOutput = std::make_shared<Tensor>(Array4D<float,2,2,2,2> {
+        Tensor myOutput = Array4D<float,2,2,2,2> {
             {
                 {
                     {{  0.7995,  0.6142},
@@ -71,12 +72,12 @@ TEST_CASE("[cpu/operator] MaxPooling(forward)", "[MaxPooling][CPU]") {
                      {0.0857,  0.6776}}
                 }
             }
-        });
-        myMaxPool->getOperator()->associateInput(0,myInput);
-        myMaxPool->getOperator()->setDataType(DataType::Float32);
-        myMaxPool->getOperator()->setBackend("cpu");
-        myMaxPool->forward();
+        };
+        op->associateInput(0,myInput);
+        op->setDataType(DataType::Float32);
+        op->setBackend("cpu");
+        op->forward();
         op->getOutput(0)->print();
-        REQUIRE(*(op->getOutput(0)) == *myOutput);
+        REQUIRE(*(op->getOutput(0)) == myOutput);
     }
 }
\ No newline at end of file
diff --git a/unit_tests/operator/Test_Memorize.cpp b/unit_tests/operator/Test_Memorize.cpp
index 45ab40c5315e88b2db48c1fba92da0ab9b587398..6c1a617e268dfa376ab154f4085dc63ef3760ea7 100644
--- a/unit_tests/operator/Test_Memorize.cpp
+++ b/unit_tests/operator/Test_Memorize.cpp
@@ -9,21 +9,22 @@
  *
  ********************************************************************************/
 
-#include <catch2/catch_test_macros.hpp>
 #include <memory>
 #include <string>
 
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/AddImpl.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/graph/Node.hpp"
 #include "aidge/graph/GraphView.hpp"
 #include "aidge/graph/OpArgs.hpp"
+#include "aidge/operator/Add.hpp"
 #include "aidge/operator/Memorize.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/scheduler/SequentialScheduler.hpp"
-
-#include "aidge/backend/cpu.hpp"
 #include "aidge/recipes/GraphViewHelper.hpp"
-
+#include "aidge/scheduler/SequentialScheduler.hpp"
 
 namespace Aidge {
 
@@ -56,10 +57,10 @@ TEST_CASE("[cpu/operator] Memorize(forward)", "[Memorize][CPU]") {
         REQUIRE_NOTHROW(scheduler.forward());
         scheduler.saveSchedulingDiagram("simple");
 
-        const auto expectedOutput = std::make_shared<Tensor>(Array1D<int, 1>{{4}});
+        const Tensor expectedOutput = Array1D<int, 1>{{4}};
         std::shared_ptr<Tensor> other = std::static_pointer_cast<OperatorTensor>(mem->getOperator())->getOutput(0);
         other->print();
-        REQUIRE((*other == *expectedOutput));
+        REQUIRE((*other == expectedOutput));
     }
 }
 } // namespace Aidge
diff --git a/unit_tests/operator/Test_PadImpl.cpp b/unit_tests/operator/Test_PadImpl.cpp
index cdd3a5f979085f3782776ce69ddd92c0d53150c4..f7823d022c8d3b228740a3df3f1d01224cd346c6 100644
--- a/unit_tests/operator/Test_PadImpl.cpp
+++ b/unit_tests/operator/Test_PadImpl.cpp
@@ -9,15 +9,17 @@
  *
  ********************************************************************************/
 
-#include <catch2/catch_test_macros.hpp>
-#include <cstdlib>
 #include <memory>
 
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/PadImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
+#include "aidge/graph/Node.hpp"
 #include "aidge/operator/Pad.hpp"
 
-#include "aidge/backend/cpu.hpp"
-
 using namespace Aidge;
 
 TEST_CASE("[cpu/operator] Pad(forward)", "[Pad][CPU]") {
diff --git a/unit_tests/operator/Test_PaddedConv.cpp b/unit_tests/operator/Test_PaddedConv.cpp
index b7584ad069336a270ed07c32d4c07552888b6587..4b76fe0638033e41adf95d3abfd10691deefe940 100644
--- a/unit_tests/operator/Test_PaddedConv.cpp
+++ b/unit_tests/operator/Test_PaddedConv.cpp
@@ -9,16 +9,16 @@
  *
  ********************************************************************************/
 
-#include <catch2/catch_test_macros.hpp>
-#include <cstdlib>
 #include <memory>
 
+#include <catch2/catch_test_macros.hpp>
+
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/PaddedConvImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
-#include "aidge/operator/MetaOperator.hpp"
+#include "aidge/graph/Node.hpp"
 #include "aidge/operator/MetaOperatorDefs.hpp"
-#include "aidge/scheduler/SequentialScheduler.hpp"
-
-#include "aidge/backend/cpu.hpp"
 
 using namespace Aidge;
 
diff --git a/unit_tests/operator/Test_ReLUImpl.cpp b/unit_tests/operator/Test_ReLUImpl.cpp
index 106d29ecfbf8ba785b4f9e5dba75daa272a86b26..eebdf7ac6c716db987c2600f098dcf9331d6a6c9 100644
--- a/unit_tests/operator/Test_ReLUImpl.cpp
+++ b/unit_tests/operator/Test_ReLUImpl.cpp
@@ -9,15 +9,16 @@
  *
  ********************************************************************************/
 
+#include <memory>
+
 #include <catch2/catch_test_macros.hpp>
 
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/ReLUImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/ReLU.hpp"
 
-#include "aidge/backend/cpu.hpp"
-
-#include <memory>
-
 
 using namespace Aidge;
 
@@ -26,17 +27,16 @@ TEST_CASE("[cpu/operator] ReLU(forward)", "[ReLU][CPU]") {
         std::shared_ptr<Tensor> input0 = std::make_shared<Tensor>(Array1D<int,10> {
             {0, 1, 2,-3, 4,-5,-6, 7, 8, 9}
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array1D<int,10> {
+        Tensor expectedOutput = Array1D<int,10> {
             {0, 1, 2, 0, 4, 0, 0, 7, 8, 9}
-        });
+        };
 
-        std::shared_ptr<Node> myReLU = ReLU();
-        auto op = std::static_pointer_cast<OperatorTensor>(myReLU -> getOperator());
+        std::shared_ptr<ReLU_Op> op = std::make_shared<ReLU_Op>();
         op->associateInput(0,input0);
         op->setDataType(DataType::Int32);
         op->setBackend("cpu");
-        myReLU->forward();
-        REQUIRE(*(op->getOutput(0)) == *expectedOutput);
+        op->forward();
+        REQUIRE(*(op->getOutput(0)) == expectedOutput);
     }
 
     SECTION("2D Tensor") {
@@ -46,20 +46,19 @@ TEST_CASE("[cpu/operator] ReLU(forward)", "[ReLU][CPU]") {
                 {-5, 4, 2,-3, 4,-5,-6, 7,-1,10}
             }
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array2D<int,2,10> {
+        Tensor expectedOutput = Array2D<int,2,10> {
             {
                 { 0, 1, 2, 0, 4, 0, 0, 7, 8, 9},
                 { 0, 4, 2, 0, 4, 0, 0, 7, 0,10}
             }
-        });
+        };
 
-        std::shared_ptr<Node> myReLU = ReLU();
-        auto op = std::static_pointer_cast<OperatorTensor>(myReLU -> getOperator());
+        std::shared_ptr<ReLU_Op> op = std::make_shared<ReLU_Op>();
         op->associateInput(0,input0);
         op->setDataType(DataType::Int32);
         op->setBackend("cpu");
-        myReLU->forward();
-        REQUIRE(*op->getOutput(0) == *expectedOutput);
+        op->forward();
+        REQUIRE(*op->getOutput(0) == expectedOutput);
     }
 
     SECTION("3D Tensor") {
@@ -75,7 +74,7 @@ TEST_CASE("[cpu/operator] ReLU(forward)", "[ReLU][CPU]") {
                 }
             }
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array3D<int,2,2,10> {
+        Tensor expectedOutput = Array3D<int,2,2,10> {
             {
                 {
                     { 0, 1, 2, 0, 4, 0, 0, 7, 8, 9},
@@ -86,15 +85,14 @@ TEST_CASE("[cpu/operator] ReLU(forward)", "[ReLU][CPU]") {
                     { 0, 4, 2, 0, 4, 0, 0, 7, 0,10}
                 }
             }
-        });
+        };
 
-        std::shared_ptr<Node> myReLU = ReLU();
-        auto op = std::static_pointer_cast<OperatorTensor>(myReLU -> getOperator());
+        std::shared_ptr<ReLU_Op> op = std::make_shared<ReLU_Op>();
         op->associateInput(0,input0);
         op->setDataType(DataType::Int32);
         op->setBackend("cpu");
-        myReLU->forward();
-        REQUIRE(*(op->getOutput(0)) == *expectedOutput);
+        op->forward();
+        REQUIRE(*(op->getOutput(0)) == expectedOutput);
     }
 
     SECTION("4D Tensor") {
@@ -122,7 +120,7 @@ TEST_CASE("[cpu/operator] ReLU(forward)", "[ReLU][CPU]") {
                 }
             }
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array4D<int,2,2,2,10> {
+        Tensor expectedOutput = Array4D<int,2,2,2,10> {
             {
                 {
                     {
@@ -145,14 +143,13 @@ TEST_CASE("[cpu/operator] ReLU(forward)", "[ReLU][CPU]") {
                     }
                 }
             }
-        });
+        };
 
-        std::shared_ptr<Node> myReLU = ReLU();
-        auto op = std::static_pointer_cast<OperatorTensor>(myReLU -> getOperator());
+        std::shared_ptr<ReLU_Op> op = std::make_shared<ReLU_Op>();
         op->associateInput(0,input0);
         op->setDataType(DataType::Int32);
         op->setBackend("cpu");
-        myReLU->forward();
-        REQUIRE(*op->getOutput(0) == *expectedOutput);
+        op->forward();
+        REQUIRE(*op->getOutput(0) == expectedOutput);
     }
 }
\ No newline at end of file
diff --git a/unit_tests/operator/Test_ReduceMeanImpl.cpp b/unit_tests/operator/Test_ReduceMeanImpl.cpp
index dd647c7ba3f90fe7f3554aae7133e97ffa9c99ba..30ffeb0dd0b584f50349c206863c7ab9ac776721 100644
--- a/unit_tests/operator/Test_ReduceMeanImpl.cpp
+++ b/unit_tests/operator/Test_ReduceMeanImpl.cpp
@@ -9,16 +9,23 @@
  *
  ********************************************************************************/
 
-#include <catch2/catch_test_macros.hpp>
+#include <algorithm>   // std::fill
+#include <cstddef>     // std::size_t
+#include <cstdint>     // std::int32_t, std::uint16_t
 #include <memory>
-#include <numeric>   // std::accumulate
-#include <random>    // std::random_device, std::mt19937, std::uniform_real_distribution
+#include <random>      // std::random_device, std::mt19937
+                       // std::uniform_int_distribution, std::uniform_real_distribution
+#include <vector>
+
+#include <catch2/catch_test_macros.hpp>
+#include <fmt/core.h>
 
+#include "aidge/backend/cpu/data/TensorImpl.hpp"
+#include "aidge/backend/cpu/operator/ReduceMeanImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/ReduceMean.hpp"
-#include "aidge/operator/Conv.hpp"
-
-#include "aidge/backend/cpu.hpp"
+#include "aidge/operator/OperatorTensor.hpp"
 #include "aidge/utils/TensorUtils.hpp"
 
 using namespace Aidge;
diff --git a/unit_tests/operator/Test_SoftmaxImpl.cpp b/unit_tests/operator/Test_SoftmaxImpl.cpp
index da6c6f0d35a1db9ad9099a40b7e83459e14a20f5..bc452a409fef0236b3021de5b41eb47453f42f75 100644
--- a/unit_tests/operator/Test_SoftmaxImpl.cpp
+++ b/unit_tests/operator/Test_SoftmaxImpl.cpp
@@ -9,14 +9,16 @@
  *
  ********************************************************************************/
 
+#include <memory>
+
 #include <catch2/catch_test_macros.hpp>
 
+#include "aidge/backend/cpu/operator/SoftmaxImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/Softmax.hpp"
-
-#include "aidge/backend/cpu.hpp"
-
-#include <memory>
+#include "aidge/utils/ArrayHelpers.hpp"
+#include "aidge/utils/TensorUtils.hpp"
 
 using namespace Aidge;
 
@@ -30,28 +32,22 @@ TEST_CASE("[cpu/operator] Softmax(forward)", "[Softmax][CPU]") {
                     0.35077620, -0.78156322, -0.98952234,  0.04166317,  1.34357309}
             }
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array2D<float,2,10> {
+        Tensor expectedOutput = Array2D<float,2,10> {
             {
                 {0.04883239, 0.11326669, 0.05974559, 0.09930880, 0.09267281, 0.03006749,
                     0.15842478, 0.24514021, 0.07825989, 0.07428131},
                 {0.05429055, 0.27136859, 0.28389078, 0.02240700, 0.06262558, 0.06087753,
                     0.01961952, 0.01593576, 0.04469007, 0.16429459}
             }
-        });
+        };
 
-        std::shared_ptr<Node> mySoftmax = Softmax(1);
-        auto op = std::static_pointer_cast<OperatorTensor>(mySoftmax -> getOperator());
+        std::shared_ptr<Softmax_Op> op = std::make_shared<Softmax_Op>(1);
         op->associateInput(0,input);
         op->setDataType(DataType::Float32);
         op->setBackend("cpu");
-        mySoftmax->forward();
-
-        float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
-        float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
-        for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
-            REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
-        }
+        op->forward();
 
+        REQUIRE(approxEq<float>(*(op->getOutput(0)), expectedOutput, 1e-5f, 1e-8f));
     }
     SECTION("4D Tensor") {
         std::shared_ptr<Tensor> input = std::make_shared<Tensor>(Array4D<float,2,3,3,3> {
@@ -80,7 +76,7 @@ TEST_CASE("[cpu/operator] Softmax(forward)", "[Softmax][CPU]") {
                 }
             }
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array4D<float,2,3,3,3> {
+        Tensor expectedOutput = Array4D<float,2,3,3,3> {
             {
                 {
                     {{0.45109013, 0.42849392, 0.43775153},
@@ -105,19 +101,14 @@ TEST_CASE("[cpu/operator] Softmax(forward)", "[Softmax][CPU]") {
                      {0.34566763, 0.32462072, 0.48979440}}
                 }
             }
-        });
+        };
 
-        std::shared_ptr<Node> mySoftmax = Softmax(1);
-        auto op = std::static_pointer_cast<OperatorTensor>(mySoftmax -> getOperator());
+        std::shared_ptr<Softmax_Op> op = std::make_shared<Softmax_Op>(1);
         op->associateInput(0,input);
         op->setDataType(DataType::Float32);
         op->setBackend("cpu");
-        mySoftmax->forward();
+        op->forward();
 
-        float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
-        float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
-        for (std::size_t i = 0; i< expectedOutput->size(); ++i) {
-            REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
-        }
+        REQUIRE(approxEq<float>(*(op->getOutput(0)), expectedOutput, 1e-5f, 1e-8f));
     }
 }
\ No newline at end of file
diff --git a/unit_tests/operator/Test_SqrtImpl.cpp b/unit_tests/operator/Test_SqrtImpl.cpp
index d630c66c8b8085e6d382841da6b7cac2c88b1dd0..aac5046003611d96d5c8111192e9fd4c5254b89d 100644
--- a/unit_tests/operator/Test_SqrtImpl.cpp
+++ b/unit_tests/operator/Test_SqrtImpl.cpp
@@ -9,14 +9,16 @@
  *
  ********************************************************************************/
 
+#include <memory>
+
 #include <catch2/catch_test_macros.hpp>
 
+#include "aidge/backend/cpu/operator/SqrtImpl.hpp"
+#include "aidge/data/DataType.hpp"
 #include "aidge/data/Tensor.hpp"
 #include "aidge/operator/Sqrt.hpp"
-
-#include "aidge/backend/cpu.hpp"
-
-#include <memory>
+#include "aidge/utils/ArrayHelpers.hpp"
+#include "aidge/utils/TensorUtils.hpp"
 
 using namespace Aidge;
 
@@ -28,26 +30,20 @@ TEST_CASE("[cpu/operator] Sqrt(forward)", "[Sqrt][CPU]") {
                 { 0.00000000,  1.84539008}
             }
         });
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array2D<float,2,2> {
+        Tensor expectedOutput = Array2D<float,2,2> {
             {
                 {4.00000000, 0.78883994},
                 {0.00000000, 1.35845140}
             }
-        });
+        };
 
-        std::shared_ptr<Node> mySqrt = Sqrt();
-        auto op = std::static_pointer_cast<OperatorTensor>(mySqrt -> getOperator());
-        mySqrt->getOperator()->associateInput(0,input);
-        mySqrt->getOperator()->setDataType(DataType::Float32);
-        mySqrt->getOperator()->setBackend("cpu");
-        mySqrt->forward();
-
-        float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
-        float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
-        for (std::size_t i = 0; i< 4; ++i) {
-            REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
-        }
+        std::shared_ptr<Sqrt_Op> op = std::make_shared<Sqrt_Op>();
+        op->associateInput(0,input);
+        op->setDataType(DataType::Float32);
+        op->setBackend("cpu");
+        op->forward();
 
+        REQUIRE(approxEq<float>(*(op->getOutput(0)), expectedOutput, 1e-5f, 1e-8f));
     }
 
     SECTION("4D Tensor") {
@@ -78,7 +74,7 @@ TEST_CASE("[cpu/operator] Sqrt(forward)", "[Sqrt][CPU]") {
             }
         });
 
-        std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array4D<float,2,3,3,3> {
+        Tensor expectedOutput = Array4D<float,2,3,3,3> {
             {
                 {
                     {{0.24936883, 0.6844717,  0.7804763},
@@ -103,19 +99,14 @@ TEST_CASE("[cpu/operator] Sqrt(forward)", "[Sqrt][CPU]") {
                      {0.3608653,  0.8571328,  0.16447252}}
                 }
             }
-        });
+        };
 
-        std::shared_ptr<Node> mySqrt = Sqrt();
-        auto op = std::static_pointer_cast<OperatorTensor>(mySqrt -> getOperator());
-        mySqrt->getOperator()->associateInput(0,input);
-        mySqrt->getOperator()->setDataType(DataType::Float32);
-        mySqrt->getOperator()->setBackend("cpu");
-        mySqrt->forward();
+        std::shared_ptr<Sqrt_Op> op = std::make_shared<Sqrt_Op>();
+        op->associateInput(0,input);
+        op->setDataType(DataType::Float32);
+        op->setBackend("cpu");
+        op->forward();
 
-        float* resPtr = static_cast<float*>(op->getOutput(0)->getImpl()->rawPtr());
-        float* expectedPtr = static_cast<float*>(expectedOutput->getImpl()->rawPtr());
-        for (std::size_t i = 0; i< 54; ++i) {
-            REQUIRE(std::abs(resPtr[i]-expectedPtr[i]) < 0.00001);
-        }
+        REQUIRE(approxEq<float>(*(op->getOutput(0)), expectedOutput, 1e-5f, 1e-8f));
     }
 }
\ No newline at end of file