How to use GoogleTest/GoogleMock to test a hash table implementation?

60 Views Asked by At

I want to write unit tests using GoogleTest/GoogleMock for a hash table implementation I am writing for practice, but I don't know what the best approach would be.

Here are the hash table interfaces:

hash_table.h

#include <vector>

#include "bucket.h"
#include "node.h"

namespace hash_table {

class HashTable {
 private:
  unsigned int hash_table_size_{0};
  std::unique_ptr<std::vector<std::unique_ptr<Bucket>>> buckets_;
  [[nodiscard]] auto GetHash(unsigned int value) const -> unsigned int;

 public:
  explicit HashTable(unsigned int size);
  auto Insert(std::unique_ptr<Node> node) -> void;
  auto Remove(unsigned int value) -> bool;
  [[nodiscard]] auto Find(unsigned int value) const
      -> std::variant<Node*, std::tuple<Node*, Node*>>;
  [[nodiscard]] auto GetBuckets() const
      -> std::vector<std::unique_ptr<Bucket>>&;
};

}  // namespace hash_table

bucket.h

#include "node.h"

namespace hash_table {

class Bucket {
 private:
  std::unique_ptr<Node> first_node_;

 public:
  Bucket();
  auto SetFirstNode(std::unique_ptr<Node> first_node) -> void;
  [[nodiscard]] auto GetFirstNode() const -> Node*;
};

}  // namespace hash_table

node.h

#include <memory>

namespace hash_table {

class Node {
 private:
  std::unique_ptr<unsigned int> value_;
  std::unique_ptr<Node> next_node_;

 public:
  Node();
  auto SetValue(std::unique_ptr<unsigned int> value) -> Node&;
  [[nodiscard]] auto GetValue() const -> unsigned int*;
  auto SetNextNode(std::unique_ptr<Node> next_node) -> Node&;
  [[nodiscard]] auto GetNextNode() const -> Node*;
  [[nodiscard]] auto GetNextNodeOwnership() -> std::unique_ptr<Node>;
};

}  // namespace hash_table

My intuition tells me that the best approach would be to somehow mock/stub a hash table data structure, and then e.g. run assertions on the Find function for different parameter values and check whether the values returned from the mocked hash table match the expected values. This could be done using a parameterized test, but it would require me to use the Insert function and Bucket and Node objects to create such a data structure, which seems like an anti-pattern since it implies that those three elements in the implementation work flawlessly.

Now I'm wondering what the best-practice approach would be.

Here's how far I got with the tests:

#include "hash_table.h"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <algorithm>
#include <tuple>

namespace hash_table {

using TupleReturnType = std::tuple<Node*, Node*>;
using VariantReturnType = std::variant<Node*, TupleReturnType>;

class MockNode : public Node {
 public:
  MOCK_METHOD(Node&, SetValue, (std::unique_ptr<unsigned int> value));
  MOCK_METHOD(unsigned int*, GetValue, (), (const));
  MOCK_METHOD(Node&, SetNextNode, (std::unique_ptr<Node> next_node));
  MOCK_METHOD(Node&, GetNextNode, (), (const));
  MOCK_METHOD(std::unique_ptr<Node>, GetNextNodeOwnership, ());
};

class MockBucket : public Bucket {
 public:
  MOCK_METHOD(void, SetFirstNode, (std::unique_ptr<Node> first_node));
  MOCK_METHOD(Node*, GetFirstNode, (), (const));
};

class MockHashTable : public HashTable {
 public:
  explicit MockHashTable(unsigned int size) : HashTable(size) {}

  MOCK_METHOD(void, Insert, (std::unique_ptr<Node> node));
  MOCK_METHOD(bool, Remove, (unsigned int value));
  MOCK_METHOD(VariantReturnType, Find, (unsigned int value), (const));
  MOCK_METHOD(std::vector<std::unique_ptr<Bucket>>&, GetBuckets, (), (const));
};

}  // namespace hash_table
0

There are 0 best solutions below