Writing Tests with a Mock Client
Mocking GCS bucket read and write
It is possible to mock GCS bucket read and write using gmock framework, this is specially useful for developer using GCS C++ client library.
Mocking Successful call of ReadObject()
Mocking of ReadObject can be achieved by mocking ObjectReadSource
. The following code snippet explains this
TEST(StorageMockingSamples, MockReadObject) {
namespace gcs = ::google::cloud::storage;
std::shared_ptr<gcs::testing::MockClient> mock =
std::make_shared<gcs::testing::MockClient>();
auto client = gcs::testing::UndecoratedClientFromMock(mock);
std::string const text = "this is a mock http response";
std::size_t offset = 0;
// Simulate a Read() call in the MockObjectReadSource object created below
auto simulate_read = [&text, &offset](void* buf, std::size_t n) {
auto const l = (std::min)(n, text.size() - offset);
std::memcpy(buf, text.data() + offset, l);
offset += l;
return gcs::internal::ReadSourceResult{
l, gcs::internal::HttpResponse{200, {}, {}}};
};
EXPECT_CALL(*mock, ReadObject)
.WillOnce([&](gcs::internal::ReadObjectRangeRequest const& request) {
EXPECT_EQ(request.bucket_name(), "mock-bucket-name") << request;
std::unique_ptr<gcs::testing::MockObjectReadSource> mock_source(
new gcs::testing::MockObjectReadSource);
::testing::InSequence seq;
EXPECT_CALL(*mock_source, IsOpen()).WillRepeatedly(Return(true));
EXPECT_CALL(*mock_source, Read).WillOnce(simulate_read);
EXPECT_CALL(*mock_source, IsOpen()).WillRepeatedly(Return(false));
return google::cloud::make_status_or(
std::unique_ptr<gcs::internal::ObjectReadSource>(
std::move(mock_source)));
});
gcs::ObjectReadStream stream =
client.ReadObject("mock-bucket-name", "mock-object-name");
// Reading the payload of http response stored in stream
std::string actual{std::istreambuf_iterator<char>(stream), {}};
EXPECT_EQ(actual, text);
stream.Close();
}
Mocking Failed call of ReadObject()
Mocking of ReadObject can be achieved by mocking ObjectReadSource
. The following code snippet explains this
TEST(StorageMockingSamples, MockReadObjectFailure) {
namespace gcs = ::google::cloud::storage;
std::shared_ptr<gcs::testing::MockClient> mock =
std::make_shared<gcs::testing::MockClient>();
auto client = gcs::testing::UndecoratedClientFromMock(mock);
std::string text = "this is a mock http response";
EXPECT_CALL(*mock, ReadObject)
.WillOnce([](gcs::internal::ReadObjectRangeRequest const& request) {
EXPECT_EQ(request.bucket_name(), "mock-bucket-name") << request;
auto* mock_source = new gcs::testing::MockObjectReadSource;
::testing::InSequence seq;
EXPECT_CALL(*mock_source, IsOpen).WillRepeatedly(Return(true));
EXPECT_CALL(*mock_source, Read)
.WillOnce(Return(google::cloud::Status(
google::cloud::StatusCode::kInvalidArgument,
"Invalid Argument")));
EXPECT_CALL(*mock_source, IsOpen).WillRepeatedly(Return(false));
std::unique_ptr<gcs::internal::ObjectReadSource> result(mock_source);
return google::cloud::make_status_or(std::move(result));
});
gcs::ObjectReadStream stream =
client.ReadObject("mock-bucket-name", "mock-object-name");
EXPECT_TRUE(stream.bad());
stream.Close();
}
Mocking Successful call of WriteObject()
Mocking of ReadObject can be achieved by mocking ObjectWriteStreambuf
. The following code snippet explains this
TEST(StorageMockingSamples, MockWriteObject) {
namespace gcs = ::google::cloud::storage;
std::shared_ptr<gcs::testing::MockClient> mock =
std::make_shared<gcs::testing::MockClient>();
auto client = gcs::testing::UndecoratedClientFromMock(mock);
gcs::ObjectMetadata expected_metadata;
using gcs::internal::CreateResumableUploadResponse;
using gcs::internal::QueryResumableUploadResponse;
EXPECT_CALL(*mock, CreateResumableUpload)
.WillOnce(Return(CreateResumableUploadResponse{"test-only-upload-id"}));
EXPECT_CALL(*mock, UploadChunk)
.WillOnce(Return(QueryResumableUploadResponse{
/*.committed_size=*/absl::nullopt,
/*.object_metadata=*/expected_metadata}));
auto stream = client.WriteObject("mock-bucket-name", "mock-object-name");
stream << "Hello World!";
stream.Close();
Mocking Failed call of WriteObject()
Mocking of ReadObject can be achieved by mocking ObjectWriteStreambuf
. The following code snippet explains this
TEST(StorageMockingSamples, MockWriteObjectFailure) {
namespace gcs = ::google::cloud::storage;
std::shared_ptr<gcs::testing::MockClient> mock =
std::make_shared<gcs::testing::MockClient>();
auto client = gcs::testing::UndecoratedClientFromMock(mock);
using gcs::internal::CreateResumableUploadResponse;
using gcs::internal::QueryResumableUploadResponse;
EXPECT_CALL(*mock, CreateResumableUpload)
.WillOnce(Return(CreateResumableUploadResponse{"test-only-upload-id"}));
EXPECT_CALL(*mock, UploadChunk)
.WillOnce(Return(google::cloud::Status{
google::cloud::StatusCode::kInvalidArgument, "Invalid Argument"}));
auto stream = client.WriteObject("mock-bucket-name", "mock-object-name");
stream << "Hello World!";
stream.Close();
EXPECT_TRUE(stream.bad());
}
The documentation for each member function in the Client class includes short snippets on how to call the function. The snippets for ReadObject() , WriteObject() , ListObjects() , and DeleteObject() are good places to continue learning about the library.