PHPackages                             trismegiste/phpunit-assert-solid - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. trismegiste/phpunit-assert-solid

ActiveLibrary[Testing &amp; Quality](/categories/testing)

trismegiste/phpunit-assert-solid
================================

Assert your SOLID compliance and coding good pratices in unit tests

v1.1.0(6y ago)914.8k↓50%MITPHPPHP &gt;=7.3

Since Dec 3Pushed 6y ago1 watchersCompare

[ Source](https://github.com/Trismegiste/phpunit-assert-solid)[ Packagist](https://packagist.org/packages/trismegiste/phpunit-assert-solid)[ RSS](/packages/trismegiste-phpunit-assert-solid/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (2)Versions (3)Used By (0)

SOLID Assertions for [PHPUnit](http://phpunit.de)
=================================================

[](#solid-assertions-for-phpunit)

Don't remind others the [SOLID](http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) guidances, do it programatically... with an axe 😄

[![Build Status](https://camo.githubusercontent.com/50bb6382c122cd96b3c8df7c51e8df6de3df3aa048281071eb1671e576021ab3/68747470733a2f2f7472617669732d63692e6f72672f547269736d6567697374652f706870756e69742d6173736572742d736f6c69642e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/Trismegiste/phpunit-assert-solid)

When
----

[](#when)

Today is the day your programer's life has changed ! You're tired to endlessly remind your team/github-users to follow [SOLID principles](http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) and [Demeter's Law](http://en.wikipedia.org/wiki/Law_of_Demeter) ? Now it's over. (With such a statement, I wage you'll read the next paragraph)

What
----

[](#what)

It's a library of assertions for the programer's best friend a.k.a : [PHPUnit](http://phpunit.de). These **assertions** are about how **classes** don't break some elementary rules of OOP, mainly the **SOLID guidances** and Demeter's Law.

How
---

[](#how)

This library does nothing by itself. It is NOT a static code analyzer, it is more a helper for putting assertions on SOLID compliance in unit tests. If a static code analyzer is a cure, this tool is a vaccine.

### Add this lib to your project with [composer](http://getcomposer.org) :

[](#add-this-lib-to-your-project-with-composer-)

```
 $ composer.phar require --dev trismegiste/phpunit-assert-solid:dev-master
```

### use the trait in your phpunit unit test class :

[](#use-the-trait-in-your-phpunit-unit-test-class-)

```
class ProjectTest extends PHPUnit_Framework_TestCase
{
    use \Trismegiste\SolidAssert\GoodPractice;  // assertInterfaceHintedParameter('BadProject\Case1');
    }

    public function testHollywoodPrinciple()
    {
        // this one for Hollywood Principle :
        $this->assertHollywoodPrinciple('BadProject\Case4');
    }

    // ...
}
```

see full example in ./examples/SimpleTest.php

API
---

[](#api)

In all assertions, $fqcn means "fully qualified class name" as described as in PSR-0

### assertTypeHintedMethodReturn($fqcn)

[](#asserttypehintedmethodreturnfqcn)

Asserts if all methods of a given class have a return type

### assertInterfaceHintedParameter($fqcn)

[](#assertinterfacehintedparameterfqcn)

Asserts if all methods parameters for a given class/interface are type-hinted with interface and not class. (loose-coupling)

### assertNoMethodWithoutContract($fqcn)

[](#assertnomethodwithoutcontractfqcn)

Asserts if all public methods for a given class are first declared in an interface implemented by this class. (design by contract and ISP)

### assertSmallApi($fqcn, $size)

[](#assertsmallapifqcn-size)

Asserts if a given class has a small public api. Too many methods means too many responsibilities (SRP). Default size is 5

### assertHollywoodPrinciple($fqcn)

[](#asserthollywoodprinciplefqcn)

Asserts there is no "new" nor Singleton calls in a given class. This ensures object dependencies are injected in this class, not created nor requested (DIP). A variant is "don't ask, tell".

### assertLiskovCompliant($fqcn)

[](#assertliskovcompliantfqcn)

Asserts there is no "reflection tricks" which would undermine LSP : is\_subclass\_of, instanceof, method\_exists and class\_uses. There is exception for interfaces because, it is less dangerous and a common pattern.

### assertNotStaticFactory($fqcn)

[](#assertnotstaticfactoryfqcn)

Asserts there is no new in a static method (typically singletons and static factories are use-case) because it is a violation of OCP (and DIP as edge-effect). Standard creational design patterns (Factory Method, Builder...) are not targeted by this assertion.

### assertDemeterLawCompliant($fqcn)

[](#assertdemeterlawcompliantfqcn)

Asserts a class only knows itself and its close neighbours (Law of Demeter). This checking is very crude so I can't garantee it will work efficiently. Experimental.

### assertNoHiddenCoupling($fqcn)

[](#assertnohiddencouplingfqcn)

Detects if parameters passed on to methods are actually objects without type-hinting which is a bad practice (design by contract violation). Can't detect php tricks like reflection and call\_user\_func\*().

FAQ
---

[](#faq)

### How does it work ?

[](#how-does-it-work-)

It uses Reflection and also [nikic/PHPParser](https://github.com/nikic/PHP-Parser). This is the main advantage to integrate this tool into unit tests, because you have autoloading and it runs within a project unlike a static code analyzer.

### Is it efficient ?

[](#is-it-efficient-)

For performance concerns, this tool can make assertions only at the class scope, not the whole project scope, so some SOLID principles cannot be completely asserted, it's not magic. The goal is to avoid bad pratices to pollute an originally well-coded source not to be a SOLID-nazi. Think it like a "hack'n slash" for obvious bad practices.

By the way, if you think you've found another common OOP bad practice easy to detect, please contribute !

### But you cannot prevent someone to remove one of your assertion ?

[](#but-you-cannot-prevent-someone-to-remove-one-of-your-assertion-)

That's right, but the git-blame will show you who has knowingly removed it. It's much easier to track it and ignorance is no longer an excuse.

### SOLID principles are not as strict as you assert it ! Or some assertions

[](#solid-principles-are-not-as-strict-as-you-assert-it--or-some-assertions)

are not in the right principle. That's not a question but I agree nonetheless. Many bad pratices don't break one principle but two or three. The best example is the Singleton antipattern : It breaks OCP because the singleton cannot be open for extension and it will break DIP elsewhere because clients of this singleton will call for the unique instance instead of being injected with the instance. So, remember the subtitle : "with an axe" 😄

### Do you know that "testing does not mean freezing" ?

[](#do-you-know-that-testing-does-not-mean-freezing-)

Yes, that's right. Perhaps, one would remove an assertion with good reason during project development. The goal is not to put all these assertions on every class of your project.

But I think assertInterfaceHintedParameter, assertNoHiddenCoupling should work **almost** everywhere. It is essential assertInterfaceHintedParameter will pass on every interface you declare. If your class is not a factory, assertHollywoodPrinciple should work too. assertNotStaticFactory is a way to "lock" a creational design pattern.

assertNoMethodWithoutContract is very strict so it will work on a few cases (Facade, Decorator, Repository...). assertLiskovCompliant should work on model classes because if you need reflection tricks within the model, you're doing it wrong. I realize an assertion like assertLiskovCompliant has little chance to pass on a controller or a dispatcher and assertHollywoodPrinciple will fail obviously on creational design pattens. So be smart.

### Did you know one can easily workaround these assertions ?

[](#did-you-know-one-can-easily-workaround-these-assertions-)

That's right, for simplicity, this lib does not track hacks with ReflectionClass or call\_user\_func(). If somebody has the time to hack this lib, I think she must save that time and starts following SOLID.

### Is this a hating machine for your co-workers/contributors ?

[](#is-this-a-hating-machine-for-your-co-workerscontributors-)

Not at all, it's just a 1337-pass-filter to speed-up code review. I've put effort into comprehensive error messages and by following the strict guidances of phpunit assertions, so debugging failed tests will be the standard procedure as usual.

### Did you know that some code fixtures are invalid ? (example, calling parent

[](#did-you-know-that-some-code-fixtures-are-invalid--example-calling-parent)

without a base class) ? Yes, I know. The code must compil, not run. Introspection with the PhpParser is sometime a pain in the ass to explore so I kept the code at the minimum. Beside, code is sometime not really valid so this lib must adapt without throwing an error each time a property is not declared.

Soundtracks used for coding this library
----------------------------------------

[](#soundtracks-used-for-coding-this-library)

- Johann Sebastian Bach
- Dream Theater
- Ali Project

###  Health Score

32

—

LowBetter than 72% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity29

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1947 days

Total

2

Last Release

2236d ago

PHP version history (2 changes)v1.0.0PHP &gt;=5.4

v1.1.0PHP &gt;=7.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/64cc99ca21a090b2454784670e4ac49db17794d6861078eeceebdbe302365c3f?d=identicon)[trismegiste](/maintainers/trismegiste)

---

Top Contributors

[![Trismegiste](https://avatars.githubusercontent.com/u/1260026?v=4)](https://github.com/Trismegiste "Trismegiste (55 commits)")

---

Tags

phpunitassertsolidanalyzerdemeter

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/trismegiste-phpunit-assert-solid/health.svg)

```
[![Health](https://phpackages.com/badges/trismegiste-phpunit-assert-solid/health.svg)](https://phpackages.com/packages/trismegiste-phpunit-assert-solid)
```

###  Alternatives

[phpunit/phpunit

The PHP Unit Testing framework.

20.0k910.7M134.8k](/packages/phpunit-phpunit)[brianium/paratest

Parallel testing for PHP

2.5k118.8M754](/packages/brianium-paratest)[beberlei/assert

Thin assertion library for input validation in business models.

2.4k96.9M570](/packages/beberlei-assert)[spatie/phpunit-snapshot-assertions

Snapshot testing with PHPUnit

69417.9M510](/packages/spatie-phpunit-snapshot-assertions)[johnkary/phpunit-speedtrap

Find and report on slow tests in your PHPUnit test suite

78137.2M122](/packages/johnkary-phpunit-speedtrap)[dg/bypass-finals

Removes final keyword from source code on-the-fly and allows mocking of final methods and classes

56426.3M456](/packages/dg-bypass-finals)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
