Mocking the Cloud Bigtable C++ Client with Google Mock
In this document we describe how to write unit tests that mock google::cloud::bigtable::Table using Google Mock. This document assumes the reader is familiar with the Google Test and Google Mock frameworks and with the Cloud Bigtable C++ Client.
Mocking a successful Table::ReadRows()
First include the headers for the Table, the mocking classes, and the Google Mock framework.
The example uses a number of aliases to save typing and improve readability:
using ::testing::ByMove;
using ::testing::ElementsAre;
using ::testing::Return;
namespace gc = ::google::cloud;
namespace cbt = ::google::cloud::bigtable;
namespace cbtm = ::google::cloud::bigtable_mocks;
Create a mock connection:
auto mock = std::make_shared<cbtm::MockDataConnection>();
Now we are going to set expectations on this mock. For this test we will have it return a RowReader that will successfully yield "r1" then "r2". A helper function, bigtable_mocks::MakeRowReader() is provided for this purpose.
Finally we present the full code for this example in the ReadRowsSuccess test.
We also provide ReadRowsFailure as an example for mocking an unsuccessful Table::ReadRows() call, plus AsyncReadRows as an example for how one might use the DataConnection to mock a Table::AsyncReadRows() call.
#include "google/cloud/bigtable/mocks/mock_data_connection.h"
#include "google/cloud/bigtable/mocks/mock_row_reader.h"
#include "google/cloud/bigtable/table.h"
#include <gmock/gmock.h>
namespace {
using ::testing::ByMove;
using ::testing::ElementsAre;
using ::testing::Return;
namespace gc = ::google::cloud;
namespace cbt = ::google::cloud::bigtable;
namespace cbtm = ::google::cloud::bigtable_mocks;
TEST(MockTableTest, ReadRowsSuccess) {
// Create a mock connection:
auto mock = std::make_shared<cbtm::MockDataConnection>();
// Set up our mock connection to return a `RowReader` that will successfully
// yield "r1" then "r2":
std::vector<cbt::Row> rows = {cbt::Row("r1", {}), cbt::Row("r2", {})};
EXPECT_CALL(*mock, ReadRowsFull)
.WillOnce(Return(ByMove(cbtm::MakeRowReader(rows))));
// Create a table with the mocked connection:
cbt::Table table(mock, cbt::TableResource("project", "instance", "table"));
// Make the table call:
auto reader = table.ReadRows(cbt::RowSet(), cbt::Filter::PassAllFilter());
// Loop over the rows returned by the `RowReader` and verify the results:
std::vector<std::string> row_keys;
for (gc::StatusOr<cbt::Row> const& row : reader) {
ASSERT_TRUE(row.ok());
row_keys.push_back(row->row_key());
}
EXPECT_THAT(row_keys, ElementsAre("r1", "r2"));
}
TEST(MockTableTest, ReadRowsFailure) {
auto mock = std::make_shared<cbtm::MockDataConnection>();
// Return a `RowReader` that yields only a failing status (no rows).
gc::Status final_status(gc::StatusCode::kPermissionDenied, "fail");
EXPECT_CALL(*mock, ReadRowsFull)
.WillOnce(Return(ByMove(cbtm::MakeRowReader({}, final_status))));
cbt::Table table(mock, cbt::TableResource("project", "instance", "table"));
cbt::RowReader reader =
table.ReadRows(cbt::RowSet(), cbt::Filter::PassAllFilter());
// In this test, we expect one `StatusOr<Row>`, that holds a bad status.
auto it = reader.begin();
ASSERT_NE(it, reader.end());
EXPECT_FALSE((*it).ok());
ASSERT_EQ(++it, reader.end());
}
TEST(TableTest, AsyncReadRows) {
// Let's use an alias to ignore fields we don't care about.
using ::testing::Unused;
// Create a mock connection, and set its expectations.
auto mock = std::make_shared<cbtm::MockDataConnection>();
EXPECT_CALL(*mock, AsyncReadRows)
.WillOnce([](Unused, auto const& on_row, auto const& on_finish, Unused,
Unused, Unused) {
// Simulate returning two rows, "r1" and "r2", by invoking the `on_row`
// callback. Verify the values of the returned `future<bool>`s.
EXPECT_TRUE(on_row(cbt::Row("r1", {})).get());
EXPECT_TRUE(on_row(cbt::Row("r2", {})).get());
// Simulate a stream that ends successfully.
on_finish(gc::Status());
});
// Create the table with a mocked connection.
cbt::Table table(mock, cbt::TableResource("project", "instance", "table"));
// These are example callbacks for demonstration purposes. Applications should
// likely invoke their own callbacks when testing.
auto on_row = [](cbt::Row const&) { return gc::make_ready_future(true); };
auto on_finish = [](gc::Status const&) {};
// Make the client call.
table.AsyncReadRows(on_row, on_finish, cbt::RowSet(),
cbt::Filter::PassAllFilter());
}
} // namespace
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-14 UTC."],[[["\u003cp\u003eThis document provides instructions on how to utilize Google Mock to create unit tests for mocking the \u003ccode\u003egoogle::cloud::bigtable::Table\u003c/code\u003e within the Cloud Bigtable C++ Client.\u003c/p\u003e\n"],["\u003cp\u003eThe latest release candidate for the Cloud Bigtable C++ Client is version 2.37.0-rc, with numerous previous versions also listed, down to version 2.11.0, each with its own respective documentation.\u003c/p\u003e\n"],["\u003cp\u003eThe \u003ccode\u003eReadRowsSuccess\u003c/code\u003e test demonstrates mocking a successful \u003ccode\u003eTable::ReadRows()\u003c/code\u003e call that returns a \u003ccode\u003eRowReader\u003c/code\u003e, which yields two rows, "r1" and "r2", and verifies the expected results.\u003c/p\u003e\n"],["\u003cp\u003eThe \u003ccode\u003eReadRowsFailure\u003c/code\u003e test demonstrates how to mock an unsuccessful \u003ccode\u003eTable::ReadRows()\u003c/code\u003e call, returning a \u003ccode\u003eRowReader\u003c/code\u003e with a failing status and no rows.\u003c/p\u003e\n"],["\u003cp\u003eThe test \u003ccode\u003eAsyncReadRows\u003c/code\u003e showcases how to use \u003ccode\u003eDataConnection\u003c/code\u003e to mock a \u003ccode\u003eTable::AsyncReadRows()\u003c/code\u003e call, showing how to create and set expectations for simulating returned rows via an \u003ccode\u003eon_row\u003c/code\u003e callback and ending the stream successfully with an \u003ccode\u003eon_finish\u003c/code\u003e callback.\u003c/p\u003e\n"]]],[],null,["Version 2.15.1keyboard_arrow_down\n\n- [2.42.0-rc (latest)](/cpp/docs/reference/bigtable/latest/bigtable-mocking)\n- [2.41.0](/cpp/docs/reference/bigtable/2.41.0/bigtable-mocking)\n- [2.40.0](/cpp/docs/reference/bigtable/2.40.0/bigtable-mocking)\n- [2.39.0](/cpp/docs/reference/bigtable/2.39.0/bigtable-mocking)\n- [2.38.0](/cpp/docs/reference/bigtable/2.38.0/bigtable-mocking)\n- [2.37.0](/cpp/docs/reference/bigtable/2.37.0/bigtable-mocking)\n- [2.36.0](/cpp/docs/reference/bigtable/2.36.0/bigtable-mocking)\n- [2.35.0](/cpp/docs/reference/bigtable/2.35.0/bigtable-mocking)\n- [2.34.0](/cpp/docs/reference/bigtable/2.34.0/bigtable-mocking)\n- [2.33.0](/cpp/docs/reference/bigtable/2.33.0/bigtable-mocking)\n- [2.32.0](/cpp/docs/reference/bigtable/2.32.0/bigtable-mocking)\n- [2.31.0](/cpp/docs/reference/bigtable/2.31.0/bigtable-mocking)\n- [2.30.0](/cpp/docs/reference/bigtable/2.30.0/bigtable-mocking)\n- [2.29.0](/cpp/docs/reference/bigtable/2.29.0/bigtable-mocking)\n- [2.28.0](/cpp/docs/reference/bigtable/2.28.0/bigtable-mocking)\n- [2.27.0](/cpp/docs/reference/bigtable/2.27.0/bigtable-mocking)\n- [2.26.0](/cpp/docs/reference/bigtable/2.26.0/bigtable-mocking)\n- [2.25.1](/cpp/docs/reference/bigtable/2.25.1/bigtable-mocking)\n- [2.24.0](/cpp/docs/reference/bigtable/2.24.0/bigtable-mocking)\n- [2.23.0](/cpp/docs/reference/bigtable/2.23.0/bigtable-mocking)\n- [2.22.1](/cpp/docs/reference/bigtable/2.22.1/bigtable-mocking)\n- [2.21.0](/cpp/docs/reference/bigtable/2.21.0/bigtable-mocking)\n- [2.20.0](/cpp/docs/reference/bigtable/2.20.0/bigtable-mocking)\n- [2.19.0](/cpp/docs/reference/bigtable/2.19.0/bigtable-mocking)\n- [2.18.0](/cpp/docs/reference/bigtable/2.18.0/bigtable-mocking)\n- [2.17.0](/cpp/docs/reference/bigtable/2.17.0/bigtable-mocking)\n- [2.16.0](/cpp/docs/reference/bigtable/2.16.0/bigtable-mocking)\n- [2.15.1](/cpp/docs/reference/bigtable/2.15.1/bigtable-mocking)\n- [2.14.0](/cpp/docs/reference/bigtable/2.14.0/bigtable-mocking)\n- [2.13.0](/cpp/docs/reference/bigtable/2.13.0/bigtable-mocking)\n- [2.12.0](/cpp/docs/reference/bigtable/2.12.0/bigtable-mocking)\n- [2.11.0](/cpp/docs/reference/bigtable/2.11.0/bigtable-mocking) \n\nMocking the Cloud Bigtable C++ Client with Google Mock\n======================================================\n\nIn this document we describe how to write unit tests that mock [`google::cloud::bigtable::Table`](/cpp/docs/reference/bigtable/2.15.1/classgoogle_1_1cloud_1_1bigtable_1_1Table) using Google Mock. This document assumes the reader is familiar with the Google Test and Google Mock frameworks and with the Cloud Bigtable C++ Client.\n\n### Mocking a successful Table::ReadRows()\n\nFirst include the headers for the `Table`, the mocking classes, and the Google Mock framework. \n\n #include \"google/cloud/bigtable/mocks/mock_data_connection.h\"\n #include \"google/cloud/bigtable/mocks/mock_row_reader.h\"\n #include \"google/cloud/bigtable/table.h\"\n #include \u003cgmock/gmock.h\u003e\n\nThe example uses a number of aliases to save typing and improve readability: \n\n using ::testing::ByMove;\n using ::testing::ElementsAre;\n using ::testing::Return;\n namespace gc = ::google::cloud;\n namespace cbt = ::google::cloud::bigtable;\n namespace cbtm = ::google::cloud::bigtable_mocks;\n\nCreate a mock connection: \n\n auto mock = std::make_shared\u003ccbtm::MockDataConnection\u003e();\n\nNow we are going to set expectations on this mock. For this test we will have it return a `RowReader` that will successfully yield \"r1\" then \"r2\". A helper function, `bigtable_mocks::MakeRowReader()` is provided for this purpose. \n\n std::vector\u003ccbt::Row\u003e rows = {cbt::Row(\"r1\", {}), cbt::Row(\"r2\", {})};\n EXPECT_CALL(*mock, ReadRowsFull)\n .WillOnce(Return(ByMove(cbtm::MakeRowReader(rows))));\n\nCreate a table with the mocked connection: \n\n cbt::Table table(mock, cbt::TableResource(\"project\", \"instance\", \"table\"));\n\nMake the table call: \n\n auto reader = table.ReadRows(cbt::RowSet(), cbt::Filter::PassAllFilter());\n\nTo verify the results, we loop over the rows returned by the `RowReader`: \n\n std::vector\u003cstd::string\u003e row_keys;\n for (gc::StatusOr\u003ccbt::Row\u003e const& row : reader) {\n ASSERT_TRUE(row.ok());\n row_keys.push_back(row-\u003erow_key());\n }\n EXPECT_THAT(row_keys, ElementsAre(\"r1\", \"r2\"));\n\n### Full Listing\n\nFinally we present the full code for this example in the `ReadRowsSuccess` test.\n\nWe also provide `ReadRowsFailure` as an example for mocking an unsuccessful `Table::ReadRows()` call, plus `AsyncReadRows` as an example for how one might use the `DataConnection` to mock a `Table::AsyncReadRows()` call. \n\n\n #include \"google/cloud/bigtable/mocks/mock_data_connection.h\"\n #include \"google/cloud/bigtable/mocks/mock_row_reader.h\"\n #include \"google/cloud/bigtable/table.h\"\n #include \u003cgmock/gmock.h\u003e\n\n namespace {\n\n using ::testing::ByMove;\n using ::testing::ElementsAre;\n using ::testing::Return;\n namespace gc = ::google::cloud;\n namespace cbt = ::google::cloud::bigtable;\n namespace cbtm = ::google::cloud::bigtable_mocks;\n\n TEST(MockTableTest, ReadRowsSuccess) {\n // Create a mock connection:\n auto mock = std::make_shared\u003ccbtm::MockDataConnection\u003e();\n\n // Set up our mock connection to return a `RowReader` that will successfully\n // yield \"r1\" then \"r2\":\n std::vector\u003ccbt::Row\u003e rows = {cbt::Row(\"r1\", {}), cbt::Row(\"r2\", {})};\n EXPECT_CALL(*mock, ReadRowsFull)\n .WillOnce(Return(ByMove(cbtm::MakeRowReader(rows))));\n\n // Create a table with the mocked connection:\n cbt::Table table(mock, cbt::TableResource(\"project\", \"instance\", \"table\"));\n\n // Make the table call:\n auto reader = table.ReadRows(cbt::RowSet(), cbt::Filter::PassAllFilter());\n\n // Loop over the rows returned by the `RowReader` and verify the results:\n std::vector\u003cstd::string\u003e row_keys;\n for (gc::StatusOr\u003ccbt::Row\u003e const& row : reader) {\n ASSERT_TRUE(row.ok());\n row_keys.push_back(row-\u003erow_key());\n }\n EXPECT_THAT(row_keys, ElementsAre(\"r1\", \"r2\"));\n }\n\n TEST(MockTableTest, ReadRowsFailure) {\n auto mock = std::make_shared\u003ccbtm::MockDataConnection\u003e();\n\n // Return a `RowReader` that yields only a failing status (no rows).\n gc::Status final_status(gc::StatusCode::kPermissionDenied, \"fail\");\n EXPECT_CALL(*mock, ReadRowsFull)\n .WillOnce(Return(ByMove(cbtm::MakeRowReader({}, final_status))));\n\n cbt::Table table(mock, cbt::TableResource(\"project\", \"instance\", \"table\"));\n cbt::RowReader reader =\n table.ReadRows(cbt::RowSet(), cbt::Filter::PassAllFilter());\n\n // In this test, we expect one `StatusOr\u003cRow\u003e`, that holds a bad status.\n auto it = reader.begin();\n ASSERT_NE(it, reader.end());\n EXPECT_FALSE((*it).ok());\n ASSERT_EQ(++it, reader.end());\n }\n\n TEST(TableTest, AsyncReadRows) {\n // Let's use an alias to ignore fields we don't care about.\n using ::testing::Unused;\n\n // Create a mock connection, and set its expectations.\n auto mock = std::make_shared\u003ccbtm::MockDataConnection\u003e();\n EXPECT_CALL(*mock, AsyncReadRows)\n .WillOnce([](Unused, auto const& on_row, auto const& on_finish, Unused,\n Unused, Unused) {\n // Simulate returning two rows, \"r1\" and \"r2\", by invoking the `on_row`\n // callback. Verify the values of the returned `future\u003cbool\u003e`s.\n EXPECT_TRUE(on_row(cbt::Row(\"r1\", {})).get());\n EXPECT_TRUE(on_row(cbt::Row(\"r2\", {})).get());\n // Simulate a stream that ends successfully.\n on_finish(gc::Status());\n });\n\n // Create the table with a mocked connection.\n cbt::Table table(mock, cbt::TableResource(\"project\", \"instance\", \"table\"));\n\n // These are example callbacks for demonstration purposes. Applications should\n // likely invoke their own callbacks when testing.\n auto on_row = [](cbt::Row const&) { return gc::make_ready_future(true); };\n auto on_finish = [](gc::Status const&) {};\n\n // Make the client call.\n table.AsyncReadRows(on_row, on_finish, cbt::RowSet(),\n cbt::Filter::PassAllFilter());\n }\n\n } // namespace"]]