diff --git a/src/utils/Table.hpp b/src/utils/Table.hpp
index 5f621ab2719e93ea63d3be610818aab1cb164665..cd380661b5b59d33f20812f969f9df7b93cd5a73 100644
--- a/src/utils/Table.hpp
+++ b/src/utils/Table.hpp
@@ -9,6 +9,8 @@
 
 #include <Kokkos_CopyViews.hpp>
 
+#include <iostream>
+
 template <typename DataType>
 class [[nodiscard]] Table
 {
@@ -126,6 +128,18 @@ class [[nodiscard]] Table
 #endif   // NDEBUG
   }
 
+  friend std::ostream& operator<<(std::ostream& os, const Table& t)
+  {
+    for (size_t i = 0; i < t.numberOfRows(); ++i) {
+      os << i << '|';
+      for (size_t j = 0; j < t.numberOfColumns(); ++j) {
+        os << ' ' << j << ':' << NaNHelper(t(i, j));
+      }
+      os << '\n';
+    }
+    return os;
+  }
+
   PUGS_INLINE
   Table() = default;
 
diff --git a/tests/test_Table.cpp b/tests/test_Table.cpp
index 5372c697dc8d8bde1e2039141a8d8e226e7a68d3..a89344b75262a2eb3322589b613d6add8ae5764e 100644
--- a/tests/test_Table.cpp
+++ b/tests/test_Table.cpp
@@ -158,27 +158,62 @@ TEST_CASE("Table", "[utils]")
 
   SECTION("checking for Kokkos::View encaspulation")
   {
-    {
-      Kokkos::View<double**> kokkos_view("anonymous", 10, 3);
-      for (size_t i = 0; i < 10; ++i) {
-        for (size_t j = 0; j < 3; ++j) {
-          kokkos_view(i, j) = 3 * i + j;
-        }
+    Kokkos::View<double**> kokkos_view("anonymous", 10, 3);
+    for (size_t i = 0; i < 10; ++i) {
+      for (size_t j = 0; j < 3; ++j) {
+        kokkos_view(i, j) = 3 * i + j;
       }
+    }
 
-      Table table = encapsulate(kokkos_view);
+    Table table = encapsulate(kokkos_view);
 
-      REQUIRE(table.numberOfRows() == kokkos_view.extent(0));
-      REQUIRE(table.numberOfColumns() == kokkos_view.extent(1));
-      for (size_t i = 0; i < table.numberOfRows(); ++i) {
-        for (size_t j = 0; j < table.numberOfColumns(); ++j) {
-          REQUIRE(&table(i, j) == &kokkos_view(i, j));
-        }
+    REQUIRE(table.numberOfRows() == kokkos_view.extent(0));
+    REQUIRE(table.numberOfColumns() == kokkos_view.extent(1));
+    for (size_t i = 0; i < table.numberOfRows(); ++i) {
+      for (size_t j = 0; j < table.numberOfColumns(); ++j) {
+        REQUIRE(&table(i, j) == &kokkos_view(i, j));
       }
     }
   }
 
+  SECTION("output")
+  {
+    Table<double> table(3, 2);
+    table(0, 0) = 1;
+    table(0, 1) = 3;
+    table(1, 0) = 7;
+    table(1, 1) = -2;
+    table(2, 0) = 4;
+    table(2, 1) = -5;
+    std::ostringstream table_ost;
+    table_ost << table;
+
+    std::ostringstream ref_ost;
+    ref_ost << "0| " << 0 << ':' << 1. << ' ' << 1 << ':' << 3. << '\n';
+    ref_ost << "1| " << 0 << ':' << 7. << ' ' << 1 << ':' << -2. << '\n';
+    ref_ost << "2| " << 0 << ':' << 4. << ' ' << 1 << ':' << -5. << '\n';
+
+    REQUIRE(table_ost.str() == ref_ost.str());
+  }
+
 #ifndef NDEBUG
+  SECTION("output with signaling NaN")
+  {
+    Table<double> table(3, 2);
+    table(0, 0) = 1;
+    table(1, 1) = -2;
+    table(2, 1) = -5;
+    std::ostringstream table_ost;
+    table_ost << table;
+
+    std::ostringstream ref_ost;
+    ref_ost << "0| " << 0 << ':' << 1. << ' ' << 1 << ":nan\n";
+    ref_ost << "1| " << 0 << ":nan " << 1 << ':' << -2. << '\n';
+    ref_ost << "2| " << 0 << ":nan " << 1 << ':' << -5. << '\n';
+
+    REQUIRE(table_ost.str() == ref_ost.str());
+  }
+
   SECTION("checking for bounds violation")
   {
     REQUIRE_THROWS_AS(a(4, 0), AssertError);