This framework allows testing components without loading them into the server.
It's achieved by using the "minimal chassis" library to create a test harness to test a component and a service defined by it.
The architecture is as follows:
- The gunit test executable defines a special gmock test suite class that sets up the test harness during its construction.
- the main method initializes the gmock test framework and runs it.
The test harness consists of:
- a locally defined test harness "component" in the executable that implements mock test services that the component-under-test requires.
- machinery to init the minimal chassis, to load the harness component and the component under test and to fetch a reference to the service under test into a test suite member variable for the tests to use.
Component testing Howto
Imagine we have a component called "foo" that requires service a bar and implements a service called foo_svc. The files for this are below:
The foo files
include/mysql/components/services/service_foo.h
#define END_SERVICE_DEFINITION(name)
A macro to end the last Service definition started with the BEGIN_SERVICE_DEFINITION macro.
Definition: service.h:91
#define BEGIN_SERVICE_DEFINITION(name)
Declares a new Service.
Definition: service.h:86
#define DECLARE_BOOL_METHOD(name, args)
Declares a method that returns bool as a part of the Service definition.
Definition: service.h:112
include/mysql/components/services/service_bar.h
components/foo/component_foo.cc
return service_bar->mtd_bar(param);
}
svc_foo_mtd_foo
Kerberos Client Authentication nullptr
Definition: auth_kerberos_client_plugin.cc:251
Specifies macros to define Components.
#define END_COMPONENT_REQUIRES()
A macro to end the last declaration started with the BEGIN_COMPONENT_REQUIRES.
Definition: component_implementation.h:387
#define PROVIDES_SERVICE(component, service)
Declare a Service Implementation provided by a Component.
Definition: component_implementation.h:194
#define BEGIN_COMPONENT_REQUIRES(name)
A macro to specify requirements of the component.
Definition: component_implementation.h:223
#define REQUIRES_SERVICE(service)
Adds a Service requirement with a pointer to placeholder to the list of components.
Definition: component_implementation.h:305
#define REQUIRES_SERVICE_PLACEHOLDER(service)
Create a service placeholder, based on the service name.
Definition: component_implementation.h:280
#define BEGIN_COMPONENT_METADATA(name)
A macro to specify metadata of the component.
Definition: component_implementation.h:398
#define END_COMPONENT_METADATA()
A macro to end the last declaration started with the BEGIN_COMPONENT_METADATA.
Definition: component_implementation.h:413
#define DECLARE_COMPONENT(source_name, name)
Declares a component.
Definition: component_implementation.h:165
#define END_COMPONENT_PROVIDES()
A macro to end the last declaration started with the BEGIN_COMPONENT_PROVIDES.
Definition: component_implementation.h:204
#define METADATA(key, value)
Adds a Service requirement with a pointer to placeholder to the list of components.
Definition: component_implementation.h:407
#define END_DECLARE_COMPONENT()
A macro to end the last declaration of a Component.
Definition: component_implementation.h:173
#define BEGIN_COMPONENT_PROVIDES(name)
Creates a service implementation list that are provided by specified component.
Definition: component_implementation.h:183
Specifies macros to define Service Implementations.
#define BEGIN_SERVICE_IMPLEMENTATION(component, service)
Declares a Service Implementation.
Definition: service_implementation.h:62
#define END_SERVICE_IMPLEMENTATION()
A macro to end the last declaration of a Service Implementation.
Definition: service_implementation.h:67
#define DEFINE_BOOL_METHOD(name, args)
A short macro to define method that returns bool, which is the most common case.
Definition: service_implementation.h:88
Build a gunit test
Since component_foo requires service_bar we need to mock service_bar.
Thus we build a mock implementation as follows:
components/libminchassis/gunit_harness/include/mock/service_bar_empty.cc
#include "mysql/components/services/service_bar.h"
namespace service_bar_spc {
return false;
}
}
Now we will proceed to building a test harness "component" to embed in our test.
We will copy the template from components/libminchassis/gunit_harness/harness_component into our gunit directory components/foo/gunit and modify it as follows:
components/foo/gunit/test_harness_component.h
========== FILLME: Test Harness component
name goes here ======
#define HARNESS_COMPONENT_NAME foo_harness
===============================================================
#define COMPONENT_REF(name)
Defines a reference to the specified Component data info structure.
Definition: component_implementation.h:463
case opt name
Definition: sslopt-case.h:29
Carries information on the specific Component, all Service Implementations it provides,...
Definition: dynamic_loader.h:263
components/foo/gunit/test_harness_component.cc
#include "test_harness_component.h"
================ FILLME: Service
mock includes go here ================
#include "components/libminchassis/gunit_harness/include/mock/service_bar_empty.cc"
===============================================================
#define STRINGIFY(x) #x
================ Component declaration related stuff ================
================ FILLME: Service
mock refs go here ================
===================================================================
Definition: ha_mock.cc:144
#define STRINGIFY(x)
Definition: sql_event_tracking_to_audit_event_mapping.cc:26
Now we can go ahead and implement our test driver:
components/foo/gunit/test_foo.cc
#include <gtest/gtest.h>
#include "mysql/components/services/mysql_foo.h"
#include "test_harness_component.h"
namespace foo_test {
const char component[] = "component_foo";
const char service[] = "service_foo";
using FooTest =
TEST_F(FooTest, ComponentLoaded) {
ASSERT_NE(m_test_svc, nullptr);
ASSERT_TRUE(m_test_svc->is_valid());
}
TEST_F(FooTest, CallFoo) {
ASSERT_FALSE((*m_test_svc)->mtd_foo(12));
}
}
int main(
int argc,
char *argv[]) {
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
}
Implements a Gmock Test suite class to test a component.
Definition: test_harness_suite.h:55
int main(int argc, char **argv)
Definition: mysqlcheck.cc:521
#define SERVICE_TYPE(name)
Generates the standard Service type name.
Definition: service.h:76
And finally: here is the CMakeFiles.txt used for the harness component.
components/foo/gunit/CMakeLists.txt
RETURN()
ENDIF()
MYSQL_ADD_EXECUTABLE(test_foo-t
test_foo.cc
test_harness_component.cc
LINK_LIBRARIES gtest ${CMAKE_DL_LIBS} minchassis
OpenSSL::SSL OpenSSL::Crypto
SYSTEM_INCLUDE_DIRECTORIES ${GMOCK_INCLUDE_DIRS}
ADD_TEST test_foo-t
COMPONENT Test)
@ IF
Definition: sql_yacc.h:283
- See also
- TestHarnessSuite_templ