We introduced DDD concepts some time ago, in a series of articles in this blog. At that time, we proposed a simple way of using mORMot types to implement DDD in your applications. But all Domain Entitities being tied to the framework TSQLRecord class did appear as a limitation, breaking the […]
2015-05-03. Pascal Programming
I've just updated the documentation part about the SOLID Design
The former blog article (almost 4 years old!) sounds like a bit deprecated now...
This is why I would extract here an updated version of this material.
Ensure you checked the corresponding part of the mORMot documentation, which is the updated reference, and probably the easiest to read - including links to all the other documentation.
The acronym SOLID is derived from the following OOP principles (quoted from the corresponding Wikipedia article):
- Single responsibility principle: the notion that an object should have only a single responsibility;
- Open/closed principle: the notion that "software entities ... should be open for extension, but closed for modification";
- Liskov substitution principle: the notion that "objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program” - also named as "design by contract";
- Interface segregation principle: the notion that "many client specific interfaces are better than one general purpose interface.";
- Dependency inversion principle: the notion that one should "Depend upon Abstractions. Do not depend upon concretions.". Dependency injection is one method of following this principle, which is also called Inversion Of Control (aka IoC).
If you have some programming skills, those principles are general statements you may already found out by yourself. If you start doing serious object-oriented coding, those principles are best-practice guidelines you would gain following.
They certainly help to fight the three main code weaknesses:
- Rigidity: Hard to change something because every change affects too many other parts of the system;
- Fragility: When you make a change, unexpected parts of the system break;
- Immobility: Hard to reuse in another application because it cannot be disentangled from the current application.
Our framework features an integrated logging class, ready to be enabled for support and statistics.
For debugging purposes, it could be very handy to output the logging content
to a console window.
It enables interactive debugging of a Client-Server process, for instance: you can interact with the Client, then look in real time at the server console window, and inspect which requests are processed, without the need to open the log file.
Depending on the events, colors will be used to write the corresponding information. Errors will be displayed as light red, for instance.
Let's see some advanced topics about mORMot's mocking and stubbing features:
- How to handle complex values in parameters / arguments or results, like
- Stubbing via a custom delegate or callback;
- Calls tracing.
In order to fulfill the SOLID principles, two features are to be available when handling interfaces:
- Dependency injection;
- Stubbing and mocking of interfaces for proper testing.
We will show now how mORMot provides all needed features for such patterns, testing a simple "forgot my password" scenario: a password shall be computed for a given user name, then transmitted via SMS, and its record shall be updated in the database.
Our mORMot framework is now able to
stub or mock any Delphi
As usual, the best way to explain what a library does is to look at the code
Here is an example (similar to the one shipped with RhinoMocks) of verifying that when we execute the "forgot my password" scenario, we remembered to call the
Save() method properly:
procedure TMyTest.ForgotMyPassword; var SmsSender: ISmsSender; UserRepository: IUserRepository; begin TInterfaceStub.Create(TypeInfo(ISmsSender),SmsSender). Returns('Send',[true]); TInterfaceMock.Create(TypeInfo(IUserRepository),UserRepository,self). ExpectsCount('Save',qoEqualTo,1); with TLoginController.Create(UserRepository,SmsSender) do try ForgotMyPassword('toto'); finally Free; end; end;
And... that's all, since the verification will take place when
IUserRepository instance will be release.
If you want to follow the "test spy" pattern (i.e. no expectation defined a priori, but manual check after the execution), you can use:
procedure TMyTest.ForgotMyPassword; var SmsSender: ISmsSender; UserRepository: IUserRepository; Spy: TInterfaceMockSpy; begin TInterfaceStub.Create(TypeInfo(ISmsSender),SmsSender). Returns('Send',[true]); Spy := TInterfaceMockSpy.Create(TypeInfo(IUserRepository),UserRepository,self); with TLoginController.Create(UserRepository,SmsSender) do try ForgotMyPassword('toto'); finally Free; end; Spy.Verify('Save'); end;
This is something unique with our library: you can decide if you want to use
the classic "expect-run-verify" pattern, or the somewhat more direct
"run-verify" / "test spy" pattern.
With mORMot, you pick up your mocking class (either
TInterfaceMockSpy), then use it as
intended. You can even mix the two aspects in the same instance! It is just a
matter of taste and opportunity for you to use the right pattern.
We already shipped a sophisticated set of logging classes some month ago.
Since then, its features have been enhanced, and the system has been deeply interfaced with our main ORM framework. Now almost all low-level or high-level operations can be logged on request.
But since the log files tend to be huge (for instance, if you set the logging for our unitary tests, the 6,000,000 unitary tests creates a 280 MB log file), a log viewer was definitively in need.
2010-12-17. Pascal Programming
In a message posted in the EMB forum, Anthony wrote that he "inherited this stuff"... Maintaining a Delphi application pays the bills, but... is sometimes frustrating.
Here are some advices or experiment sharing.
2010-07-23. Pascal Programming
Automated Unit Testing is a great improvement in coding safe applications.
If you don't know about it, visit http://xprogramming.com/index.php then come back here, and you'll discover how we implement unit testing in a KISS way, in pure Delphi code.