As we mentioned in the previous sections, we will be building both an in-memory and a database-backed implementation of the Graph interface. To this end, we need to come up with a set of comprehensive tests to ensure that both implementations behave in exactly the same manner.
One way to achieve this is to write the tests for the first implementation and then duplicate them for each additional implementation that we may introduce in the future. However, this approach doesn't really scale well: what if we modify the Graph interface in the future? We would need to track down and update a whole bunch of tests that might be scattered across different packages.
A much better, and cleaner, approach would be to come up with a shared, implementation-agnostic test suite and then just wire it to each underlying graph implementation. I opted for this approach as it reduces the amount of maintenance that's required, while at the same time allowing us to run exactly the same set of tests against all implementations: a fairly efficient way of detecting regressions when we change one of our implementations.
But if the test suite is shared, where should it live so that we can include it in all implementation-specific test suites? The answer is to encapsulate the suite into its own dedicated testing package that our regular test code can import and use where it's needed.
The SuiteBase definition lives in the Chapter06/linkgraph/graph/graphtest package and depends on the gocheck [11] framework, which we introduced in Chapter 4, The Art of Testing. The suite includes the following groups of tests:
- Link/Edge upsert tests: These tests are designed to verify that we can insert new edges/links into the graph and that they are assigned a valid, unique ID.
- Concurrent link/edge iterator support: These tests ensure that no data races occur when the code concurrently accesses the graph's contents via multiple iterator instances.
- Partitioned iterator tests: These tests verify that if we split our graph into N partitions and assign an iterator to each partition, each iterator will receive a unique set of links/edges (that is, no item will be listed in more than one partition) and that all the iterators will process the full set of links/edges present in the graph. Additionally, the edge iterator tests ensure that each edge appears in the same partition as its source link.
- Link lookup tests: A simple set of tests that verify the graph implementation's behavior when looking up existing or unknown link IDs.
- Stale edge removal tests: A set of tests that verify that we can successfully delete stale edges from the graph using an updated-before-X predicate.
To create a test suite for a new graph implementation, all we have to do is to define a new test suite that does the following:
- Embeds SuiteBase
- Provides a suite setup helper that creates the appropriate graph instance and invokes the SetGraph method that's exposed by SuiteBase so that we can wire it to the base test suite before running any of the preceding tests