diff --git a/Makefile b/Makefile
index 89350650..9d26bc9d 100644
--- a/Makefile
+++ b/Makefile
@@ -525,7 +525,7 @@ pretty:
 	    --preserve-date \
 	    --suffix=none \
 	    --formatted \
-	   $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp
+	   $(SRCS) $(AMALGAMATED_FILE) test/src/*.cpp test/utils/*.hpp benchmarks/src/benchmarks.cpp doc/examples/*.cpp
 
 # create single header file
 amalgamate: $(AMALGAMATED_FILE)
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 76ba31d8..9ce1594c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -151,7 +151,7 @@ foreach(file ${files})
         $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated;-Wno-float-equal>
         $<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations>
     )
-    target_include_directories(${testcase} PRIVATE ${CMAKE_BINARY_DIR}/include thirdparty/doctest thirdparty/fifo_map)
+    target_include_directories(${testcase} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/utils ${CMAKE_BINARY_DIR}/include thirdparty/doctest thirdparty/fifo_map)
     target_link_libraries(${testcase} PRIVATE ${NLOHMANN_JSON_TARGET_NAME})
 
     if (JSON_Coverage)
diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp
index aa3acbc3..80a8012d 100644
--- a/test/src/unit-bson.cpp
+++ b/test/src/unit-bson.cpp
@@ -35,6 +35,7 @@ using nlohmann::json;
 #include <fstream>
 #include <sstream>
 #include <test_data.hpp>
+#include <test_utils.hpp>
 
 TEST_CASE("BSON")
 {
@@ -1263,10 +1264,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse BSON file
-                std::ifstream f_bson(filename + ".bson", std::ios::binary);
-                std::vector<std::uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_bson)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".bson");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_bson(packed));
 
@@ -1296,10 +1294,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse BSON file
-                std::ifstream f_bson(filename + ".bson", std::ios::binary);
-                std::vector<std::uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_bson)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".bson");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_bson({packed.data(), packed.size()}));
 
@@ -1314,10 +1309,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse BSON file
-                std::ifstream f_bson(filename + ".bson", std::ios::binary);
-                std::vector<std::uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_bson)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".bson");
 
                 {
                     INFO_WITH_TEMP(filename + ": output adapters: std::vector<std::uint8_t>");
diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp
index 7eaba84a..d5641327 100644
--- a/test/src/unit-cbor.cpp
+++ b/test/src/unit-cbor.cpp
@@ -39,6 +39,7 @@ using nlohmann::json;
 #include <iostream>
 #include <set>
 #include <test_data.hpp>
+#include <test_utils.hpp>
 
 namespace
 {
@@ -1920,9 +1921,7 @@ TEST_CASE("single CBOR roundtrip")
         json j1 = json::parse(f_json);
 
         // parse CBOR file
-        std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
-        std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_cbor)),
-                                    std::istreambuf_iterator<char>());
+        auto packed = utils::read_binary_file(filename + ".cbor");
         json j2;
         CHECK_NOTHROW(j2 = json::from_cbor(packed));
 
@@ -1994,10 +1993,7 @@ TEST_CASE("CBOR regressions")
             try
             {
                 // parse CBOR file
-                std::ifstream f_cbor(filename, std::ios::binary);
-                std::vector<uint8_t> vec1(
-                    (std::istreambuf_iterator<char>(f_cbor)),
-                    std::istreambuf_iterator<char>());
+                auto vec1 = utils::read_binary_file(filename);
                 json j1 = json::from_cbor(vec1);
 
                 try
@@ -2204,10 +2200,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse CBOR file
-                std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_cbor)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".cbor");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_cbor(packed));
 
@@ -2237,10 +2230,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse CBOR file
-                std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_cbor)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".cbor");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()}));
 
@@ -2255,10 +2245,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse CBOR file
-                std::ifstream f_cbor(filename + ".cbor", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_cbor)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".cbor");
 
                 if (!exclude_packed.count(filename))
                 {
@@ -2493,15 +2480,11 @@ TEST_CASE("examples from RFC 7049 Appendix A")
 
     SECTION("byte arrays")
     {
-        std::ifstream f_cbor(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.cbor", std::ios::binary);
-        std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_cbor)),
-                                    std::istreambuf_iterator<char>());
+        auto packed = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.cbor");
         json j;
         CHECK_NOTHROW(j = json::from_cbor(packed));
 
-        std::ifstream f_bin(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out", std::ios::binary);
-        std::vector<uint8_t> expected((std::istreambuf_iterator<char>(f_bin)),
-                                      std::istreambuf_iterator<char>());
+        auto expected = utils::read_binary_file(TEST_DATA_DIRECTORY "/binary_data/cbor_binary.out");
         CHECK(j == json::binary(expected));
 
         CHECK(json::to_cbor(json::binary(std::vector<uint8_t> {}, 0x42)) == std::vector<uint8_t> {0xd8, 0x42, 0x40});
diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp
index 2130c887..9275ad5e 100644
--- a/test/src/unit-msgpack.cpp
+++ b/test/src/unit-msgpack.cpp
@@ -37,6 +37,7 @@ using nlohmann::json;
 #include <iomanip>
 #include <set>
 #include <test_data.hpp>
+#include <test_utils.hpp>
 
 namespace
 {
@@ -1609,9 +1610,7 @@ TEST_CASE("single MessagePack roundtrip")
         json j1 = json::parse(f_json);
 
         // parse MessagePack file
-        std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
-        std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_msgpack)),
-                                    std::istreambuf_iterator<char>());
+        auto packed = utils::read_binary_file(filename + ".msgpack");
         json j2;
         CHECK_NOTHROW(j2 = json::from_msgpack(packed));
 
@@ -1824,10 +1823,7 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse MessagePack file
-                std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_msgpack)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".msgpack");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_msgpack(packed));
 
@@ -1857,10 +1853,7 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse MessagePack file
-                std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_msgpack)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".msgpack");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_msgpack({packed.data(), packed.size()}));
 
@@ -1875,10 +1868,7 @@ TEST_CASE("MessagePack roundtrips" * doctest::skip())
                 json j1 = json::parse(f_json);
 
                 // parse MessagePack file
-                std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_msgpack)),
-                    std::istreambuf_iterator<char>());
+                auto packed = utils::read_binary_file(filename + ".msgpack");
 
                 if (!exclude_packed.count(filename))
                 {
diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp
index 0f95bcec..ac133c0b 100644
--- a/test/src/unit-ubjson.cpp
+++ b/test/src/unit-ubjson.cpp
@@ -35,6 +35,7 @@ using nlohmann::json;
 #include <fstream>
 #include <set>
 #include <test_data.hpp>
+#include <test_utils.hpp>
 
 namespace
 {
@@ -2457,11 +2458,8 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip())
                 std::ifstream f_json(filename);
                 json j1 = json::parse(f_json);
 
-                // parse MessagePack file
-                std::ifstream f_ubjson(filename + ".ubjson", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_ubjson)),
-                    std::istreambuf_iterator<char>());
+                // parse UBJSON file
+                auto packed = utils::read_binary_file(filename + ".ubjson");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_ubjson(packed));
 
@@ -2475,7 +2473,7 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip())
                 std::ifstream f_json(filename);
                 json j1 = json::parse(f_json);
 
-                // parse MessagePack file
+                // parse UBJSON file
                 std::ifstream f_ubjson(filename + ".ubjson", std::ios::binary);
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_ubjson(f_ubjson));
@@ -2490,11 +2488,8 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip())
                 std::ifstream f_json(filename);
                 json j1 = json::parse(f_json);
 
-                // parse MessagePack file
-                std::ifstream f_ubjson(filename + ".ubjson", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_ubjson)),
-                    std::istreambuf_iterator<char>());
+                // parse UBJSON file
+                auto packed = utils::read_binary_file(filename + ".ubjson");
                 json j2;
                 CHECK_NOTHROW(j2 = json::from_ubjson({packed.data(), packed.size()}));
 
@@ -2508,11 +2503,8 @@ TEST_CASE("UBJSON roundtrips" * doctest::skip())
                 std::ifstream f_json(filename);
                 json j1 = json::parse(f_json);
 
-                // parse MessagePack file
-                std::ifstream f_ubjson(filename + ".ubjson", std::ios::binary);
-                std::vector<uint8_t> packed(
-                    (std::istreambuf_iterator<char>(f_ubjson)),
-                    std::istreambuf_iterator<char>());
+                // parse UBJSON file
+                auto packed = utils::read_binary_file(filename + ".ubjson");
 
                 {
                     INFO_WITH_TEMP(filename + ": output adapters: std::vector<uint8_t>");
diff --git a/test/utils/test_utils.hpp b/test/utils/test_utils.hpp
new file mode 100644
index 00000000..12c260e7
--- /dev/null
+++ b/test/utils/test_utils.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <cstdint> // uint8_t
+#include <fstream> // ifstream, istreambuf_iterator, ios
+#include <vector> // vector
+
+namespace utils
+{
+
+inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
+{
+    std::ifstream file(filename, std::ios::binary);
+    file.unsetf(std::ios::skipws);
+
+    file.seekg(0, std::ios::end);
+    const auto size = file.tellg();
+    file.seekg(0, std::ios::beg);
+
+    std::vector<std::uint8_t> byte_vector;
+    byte_vector.reserve(static_cast<std::size_t>(size));
+    byte_vector.insert(byte_vector.begin(), std::istream_iterator<std::uint8_t>(file), std::istream_iterator<std::uint8_t>());
+    return byte_vector;
+}
+
+} // namespace utils