Tag Archives: single responsibility principle

The quest for a c++ Dependency Injection Container library. Part 3, beginning dicpp

Dependency Injection + C++ = dicpp

The first article introduced the example problem – an almost trivial example for dependency injection. One of the implementation classes is mocked within a test to show the resulting implementation configuration flexibility.

Another library in the quest is dicpp. It is somewhat similar to sauce with little twists, hence it required some trial and error to get right after sauce. Dicpp configures the dependencies in code and allows configurable lifetime scopes.

Modules

Modules are, again, similar to sauce’s modules, as they can be simple functions for registering the bindings of interfaces to implementations.

The library uses a slightly intrusive macro that puts a special typedef in the class’ declaration. One constructor is supported and should be split into declaration and definition. The macro for the renderer looks as follows:

class DicppKeyRenderer : public IRender {
public:
	DI_CONSTRUCTOR(DicppKeyRenderer,(std::shared_ptr< IGetKeyValue > m));
...
};

Without changing the existing factory, the default implementations are used:

DicppKeyRenderer::DicppKeyRenderer(std::shared_ptr< IGetKeyValue > m) :
	pimpl ( NewKeyRenderer(m) ) { }

The module with the bindings looks as follows (dicpp_module.cpp):

void dicpp_module( di::registry& r ) {
	r.add( r.type< IGetKeyValue >().implementation<DicppJsonDecoder>() );
	r.add( r.type< IRender >     ().implementation<DicppKeyRenderer>() );
}

Mock and the Singleton scope

To set the mock expectations on an instance of a dependency, one needs to obtain a pointer to that dependency. Once again, the mock implementation of an interface is done via googlemock:

class MockModel : public IModel {
public:
	MOCK_METHOD0(Get, std::string());
};

To obtain the same instance of the mocked IModel as which gets resolved automatically, one can use a dedicated scope, such as the singleton scope. The mock is added to the module in the singleton scope:

void mock_module( di::registry& r ) {
	r.add( r
		.type<IModel>()
		.implementation<MockModel>()
		.in_scope<di::scopes::singleton>() )
	;
}

Configuring the injector

test_dicpp.cpp

The injector is the container of bindings that gets configured by adding modules:

di::injector inj;
inj.install( dicpp_module );
inj.install( mock_module );

Configuring the mock

With the modules “installed” in the injector, the singleton mock instance can be obtained:

auto mock_model = inj.construct_ptr< IModel >();

MockModel* mock_model_ptr = dynamic_cast< MockModel* >(mock_model.get());
ASSERT_TRUE( mock_model_ptr );

EXPECT_CALL(*mock_model_ptr, Get())
	.Times(AtLeast(1))
	.WillRepeatedly(Return("{ \"a\" : 1 , \"b\" : 2 }"));

Logging in dicpp

An interesting feature in dicpp is logging of the library activity. The feature can be overridden or turned off via macro definition. The construction of dependencies can be traced, such as here, slightly shortened :

[DICPP]: Registering: IGetKeyValue with implementation: DicppJsonDecoder in scope: di::scopes::no_scope
[DICPP]: Registering: IModel with implementation: MockModel in scope: di::scopes::singleton
[DICPP]: Registering: MockModel with implementation: MockModel in scope: di::scopes::no_scope
[DICPP]: Constructing: di::type_key<IModel, void>
[DICPP]: Provided type: di::type_key<IModel, void>
[DICPP]: Singleton: constructing: di::type_key<IModel, void>
[DICPP]: Generic constructing IModel with implementation: MockModel
[DICPP]: Completed constructing: di::type_key<IModel, void> with address: 0x7fd0b2600e40
...
[DICPP]: Singleton: returning existing: di::type_key<IModel, void>

As one can see, two bindings are registered for one implementation – the interface and implementation can be resolved at later time.

Summary

The rest of the example is very similar to the first and the second parts of the quest:

auto renderer = inj.construct_ptr< IRender >();
ASSERT_EQ( "a,b", renderer->Render() );

Although the library is very similar to sauce, the binding definition language doesn’t read as fluently as that of wallaroo or sauce. Further articles may elaborate on the outstanding features of either library.

Source: https://github.com/d-led/test-ioc-cpp

Updates

05.11.2014: Removed boost<->std shared_ptr conversions, as dicpp has been updated in the meanwhile

More to come…

The quest for a c++ Dependency Injection Container library. Part 2, some Sauce

Introduction

In Part 1 I have started with a list of C++ dependency injection libraries, and sketched an example problem, solved and tested with the help of Wallaroo. For the second part, Hypodermic should have been in focus, but unfortunately, no version compiled out of the box on MacOS with Clang [1. To do in 2014]. Hence, the article is about sauce, an inspiration from google-guice.

Dependency Injection using sauce

A little repetition, the example problem contains of 3 interfaces with a linear dependency graph of the implementations. Not to repeat the implementations, and not change the structure of the existing code, simple factories for the default implementations have been exposed, but not the concrete types in the headers, i.e. for the default renderer implementation:

std::shared_ptr< IRender > NewKeyRenderer(std::shared_ptr< IGetKeyValue > model) {
	return std::make_shared<KeyRenderer>(model);
};

Implementations

Simplified, the sauce solution looks as follows. Unlike in Wallaroo, in sauce, the implementations do not need to derive from a common “dependency” class. Any type can be bound to any derived class. The implementation of a renderer for the sauce example just adds a delegation to the original implementation [2. Efficiency and overhead are not considered in the first place.]:

class SauceKeyRenderer : public IRender {
public:
	SauceKeyRenderer(std::shared_ptr< IGetKeyValue > m) :
	pimpl ( NewKeyRenderer(m) )
	{ }

public:
	virtual std::string Render() {
		//...
		return pimpl->Render();
	}

private:
 	std::shared_ptr< IRender > pimpl;
};

Modules

Modules are containers of bindings of interfaces to their implementations. The easiest way to define a module is to provide a function with the signature void (* module)(sauce::Binder &).

Here’s the self-explaining module:

void render_module(sauce::Binder& b) {
	b.bind<IRender>().to<SauceKeyRenderer(IGetKeyValue&)>();
}

Once again, obviously, the type doesn’t have to leak outside the module due to inversion of control.

Note that the IGetKeyValue dependency of SauceKeyRenderer is injected via the constructor parameter, enabling automatic dependency resolution at later time.

Injectors

Instances of the bound interfaces are obtainable from injectors, which can be constructed from a collection of modules:

sauce::shared_ptr<Injector> injector = Modules()
	.add(render_module)
	.add(decoder_module)
	.add(model_module)
	.createInjector()
;

Resolving the dependencies

The hello-world example of resolving the dependencies is one simple line:

sauce::shared_ptr<IRender> renderer = injector->get<IRender>();

In this case, SauceKeyRenderer will get resolved and two other dependencies will be automatically instantiated and injected (see test_sauce.cpp).

Mocking and singletons

Sauce allows for different lifetime models of the interface instances. Singletons are possible with the concept of scoped injectors, in which, the instances are shared.

For googlemock getting the resolved instance is crucial, since the expectations are bound to an instance of the mocked class. With automatic dependency resolution and no hacks, the interface IModel would resolve to a new instance in the test. Hence, unless a way to use the shared instance lifetime inside the test is found, the mock is implemented trivially without googlemock.

Summary

This article is once again a short intro into the paradigm of another Dependency Injection library sauce. A more elaborate intro can be read in sauce’s tutorial test suite.

Source: https://github.com/d-led/test-ioc-cpp

More to come…