Qafoo GmbH - passion for software quality

Help you and your team benefit from new perspectives on cutting-edge quality engineering techniques and tools through the Qafoo team weblog.

By Benjamin Eberlei, first published at Tue, 11 Jul 2017 09:59:39 +0200

Download our free e-book "Crafting Quality Software" with a selection of the finest blog posts as PDF or EPub.

Crafting Quality Software

You can also buy a printed version of the book on Amazon or on epubli.

Refactoring Singleton Usage to get Testable Code

So your code base is littered with singletons and using them? Don't worry, you can start refactoring them out of your code base class by class and introduce increased testability at every step. This strategy is very simple to implement and the propability of breaking your code is very low, especially when you are becoming more experienced with this technique.

Take the following example code of a SearchService that acceses a singleton to perform its work:

class SearchService { public function searchAction($queryString, $type) { /** @var $solarium \Solarium_Client */ $solarium = Solarium::getInstance(); $select = $solarium->createSelect(); // More and complex filtering logic to test $result = $solarium->query($select); return $result; } }

To make this code testable without the singleton, we can use the lazy initialization pattern. The first step is to extract the method for the line that is fetching the singleton:

public function searchAction($queryString, $type) { /** @var $solarium \Solarium_Client */ $solarium = $this->getSolarium(); // ... } protected function getSolarium() { return Solarium::getInstance(); }

You now have two options for testability. The most obvious is to create a test class that extends the original SearchService and overwrites the protected getSolarium to return a mock. But it is not very flexible and additional classes necessary for testing are not a good practice to follow.

Instead introduce a new instance variable and fetch the singleton only if this is null, making use of the so called lazy initialization pattern:

private $solarium; private function getSolarium() { if ($this->solarium === null) { $this->solarium = Solarium::getInstance(); } return $this->solarium; } public function setSolarium(\Solarium_Client $solarium) { $this->solarium = $solarium; }

Since you would want to use constructor injection for all mandatory dependencies you could also introduce an optional constructor argument, like:

private $solarium; public function __construct(\Solarium_Client $solarium = null) { $this->solarium = $solarium ?: Solarium::getInstance(); }

Now this code is already testable using mocks:

class SearchServiceTest extends PHPUnit_Framework_TestCase { public function testSearchFilter() { $solariumMock = \Phake::getMock(SolariumClient::class); $service = new SearchService($solariumMock); \Phake::when($solarium)->createSelect()->thenReturn(new \Solarium_Query_Select($solarium)); $service->search('Foobar', 'some_type'); \Phake::verify($solarium)->query(\Phake::capture($select)); // Perform assertions on $select } }

If you perform this refactoring often you can entirely remove singletons from parts of your code base and move towards a more testable dependency injection.

Download our free e-book "Crafting Quality Software" with a selection of the finest blog posts as PDF or EPub.

Crafting Quality Software

You can also buy a printed version of the book on Amazon or on epubli.

Get Technical Insights With Our Newsletter

Stay up to date with regular new technological insights by subscribing to our newsletter. We will send you articles to improve your developments skills.

Comments

  • TeslaWhaph on Sat, 15 Jul 2017 22:09:41 +0200

    You may add paperwork and reschedule some of the timings for virtually every regarding the items during typically the wedding schedule and listing. The checklist is relatively decent, but typically the budget tool isn't also working any more. As a matter of fact, the checklist performs an exceptionally important role in your wedding planning! Easy to employ and I love the checklist feature that provides a timeline for suggesting when things should be done for your date!
    In recent years we now have seen revival in the popularity of typically the traditional wedding style. They take your current guests into account in order that you don't plan your wedding party within a tree house together with no seating. Budget calculator - this is usually an area that actually bears close scrutiny, it is very easy to overspend when it comes to buying things for a wedding. WEDDING VENUE TOURS - Get one step closer to finding the perfect venue together with tour scheduling, available immediately on venue profiles.
    Its the perfect app which keeps you on monitor and on budget when it comes to organizing your wedding. Working upon our budget employing their app also aided us within not missing any main details. Sometimes our fiance would change anything within the guest list plus it wouldn't be demonstrated when I opened the app on my telephone.
    You can add paperwork and reschedule some of the timings for virtually every of the items during the particular wedding schedule and record. The checklist will be relatively decent, but the budget tool isn't also working any more. In fact, the checklist takes on an incredibly important role in your wedding planning! Easy to employ and I love the particular checklist feature that offers a timeline for suggesting when things should become done for your day!
    With this, you can acquire in touch with the wedding planner as well, who can help you to make a checklist with the guidance of the specialists & professionals. Having <a href=http://www.virtualdragon.net/>http://www.virtualdragon.net/</a> a carefully created wedding checklist, you may keep a track of just how the things are progressing, and they are the actual effects in consensus using the organized results or not.