PHPackages                             rockylars/faker - 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. rockylars/faker

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

rockylars/faker
===============

Simple class/method faking tool like Mockery and Prophecy to make tests focus on one service at a time

1.3.0(2y ago)09[5 issues](https://github.com/Rockylars/Faker/issues)[1 PRs](https://github.com/Rockylars/Faker/pulls)MITPHPPHP &gt;=8.0CI passing

Since Nov 10Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/Rockylars/Faker)[ Packagist](https://packagist.org/packages/rockylars/faker)[ RSS](/packages/rockylars-faker/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (7)Dependencies (26)Versions (9)Used By (0)

### Introduction

[](#introduction)

Welcome to the world of single service testing with my favorite little project, Faker. It isn't much, but it will do what you need, simply create a class and make it extend Faker and implement the service's interface. I recommend creating a separate folder in your tests folder called "fake" to keep them from getting lost in your test files. I don't recommend using them in functional tests, just integration and unit tests.

### History

[](#history)

Faker is something I've made through in class methods around March of 2023 while working at [Future500](https://future500.nl/) on a project for my former company, [FinanceMatters](https://www.financematters.nl/)/[BondCenter](https://www.bondcenter.nl/), great guys in both of them. Over the next month more functions were added and due to the size of some classes, the methods were copied over to simplify the procedure. With PHP 8 turning throws into statements, the code was very compact, but some more testing revealed it needed to be a bit less compressed. Months passed and due to unfortunate circumstances out of my control, my partnership with the companies ended a 5 year long relationship. Luckily, the people there are really kind and also were sadly not *that* interested in the fun i've had with Faker, so they allowed me to keep it and distribute it as a package.

So here it is, the framework I've built because I highly disliked working with [prophesizing](https://github.com/phpspec/prophecy) and found [mocking](https://github.com/mockery/mockery) to be too convoluted and not simple enough. This simple abstract class allows you to build fake classes to your heart's content, without PHPStan ever yelling at you. They are made to be as simple as possible with a later addition of some `getAllCalls..` methods to not technically require a new check whenever you add a new method.

### Usage

[](#usage)

For unit tests, I recommend faking everything, but some classes shouldn't be faked and instead be kept as half active. Such half active classes are for example a fake clock with a `updateTime()` method inside.

For integration tests, only fake what you need to fake, don't fake things like the connection when you are testing a repository, but you can then use fake things like a Guzzle client. On that note, don't actually use Faker for your logger, you will have many calls to logger but will already be testing the output and don't care much for a duplicate input. For a logger, it's best to just array collect it and "fake" it like that, other classes like that where you don't own the deeper layers should get the same array collection treatment. However, with all that said, you do you.

### Future

[](#future)

I will add a method that adds a count check between the amount of responses set up and the amount of calls done, similar to something Mockery offers. This is rather useful of course if you have a lot of responses or set up data but missed that you didn't actually see anything go in, happens when you have a lot of fake classes set up for one service.

### Examples

[](#examples)

```
final class FakeUserRepository extends Faker implements UserRepositoryInterface
{
    public const FUNCTION_GET_USER_BY_ID = 'getUserById';
    public const FUNCTION_GET_USERS = 'getUsers';
    public const FUNCTION_UPDATE_LAST_LOGIN = 'updateLastLogin';
    public const FUNCTION_DELETE_USER = 'deleteUser';

    public function getUserById(int $userId): User
    {
        return $this->fakeCall(__FUNCTION__, [
            'userId' => $userId,
        ]);
    }

    /** @return array */
    public function getUsers(): array
    {
        return $this->fakeCall(__FUNCTION__, [
            'a call was made',
        ]);
    }

    public function updateLastLogin(int $userId): void
    {
        $this->fakeCall(__FUNCTION__, [
            'userId' => $userId,
        ]);
    }

    public function deleteUser(int $userId): void
    {
        $this->fakeCall(__FUNCTION__, [
            'userId' => $userId,
        ]);
    }
}
```

```
final class DeleteUserServiceCest
{
    private DeleteUserService $deleteUserService;
    private FakeLogger $fakeLogger;
    private FakeUserRepository $fakeUserRepository;

    public function _before(UnitTester $tester): void
    {
        $this->deleteUserService = new DeleteUserService(
            $this->fakeLogger = new FakeLogger(),
            $this->fakeUserRepository = new FakeUserRepository()
        );
    }

    public function deleteUserWillCheckAndDeleteUserByIdIfNothingIsLinked(UnitTester $tester): void
    {
        $this->fakeUserRepository->setResponsesFor(FakeUserRepository::FUNCTION_GET_USER_BY_ID, [
            [Faker::ACTION_RETURN => new User(
                id: 1,
                name: 'Rocky',
                isAdmin: false,
                lastLogin: DateTimeImmutable::createFromFormat(
                    '!Y-m-d H:i:s',
                    '2023-02-17 12:13:14',
                    new \DateTimeZone('Europe/Amsterdam')
                ),
            )],
        ]);
        $this->fakeUserRepository->setResponsesFor(FakeUserRepository::FUNCTION_DELETE_USER, [
            [Faker::ACTION_VOID => null],
        ]);

        $this->deleteUserService->deleteUser(1);

        $tester->assertSame(
            [
                [
                    'level' => 'debug',
                    'message' => 'User 1 was deleted',
                    'context' => [],
                ],
            ],
            $this->fakeLogger->getLogs(),
        );
        $tester->assertSame(
            [
                FakeUserRepository::FUNCTION_DELETE_USER => [
                    [
                        'userId' => 1,
                    ],
                ],
                FakeUserRepository::FUNCTION_GET_USER => [
                    [
                        'userId' => 1,
                    ],
                ],
            ],
            $this->fakeUserRepository->getAllCallsInStyleSorted()
        );
    }
}
```

Keep in mind that if you use `expectException` and `expectExceptionMessage` instead of `expectThrowable` you should use the following code to wrap your call as those will silently ignore the asserts below it otherwise.

```
// Using expectException and expectExceptionMessage will stop the test at the error, so a try catch is used instead.
$exceptionWasCaught = false;
try {
    // Call that will throw an exception
} catch (\Throwable $throwable) {
    // Do not assert like this on natural exceptions as those generate traces and such you can't just replicate.
    self::assertEquals(
        new \RuntimeException(
            "something happened",
            301
        ),
        $throwable
    );
    $exceptionWasCaught = true;
}
self::assertTrue($exceptionWasCaught);
```

### Set up the project for commits on Linux

[](#set-up-the-project-for-commits-on-linux)

1. Have Docker functional, you don't need an account for this.
2. Have a GitHub account (obviously) for commits.
3. Get an SSH token set up (preferably id\_ed25519) and hooked up to your GitHub account.
    - If not, you won't be able to pull/push anything properly.
4. Get the project downloaded and `cd` into the folder.
    - If you plan to make any PR's and don't have rights, make a fork first, grab that, and then attempt to merge PR's of that in.
5. Make sure that running `git config --global --list` and `git config --list` both show `user.email=YOUR_GITHUB_EMAIL`and `user.name=YOUR_GITHUB_USER_NAME`.
    - If not, here's the steps to fix it:
    - Set the value for the project and unset the one for local, otherwise set it for local only.
    - Your commits won't link to an account if this is not done.
6. Make sure that running `groups` shows `docker` in it.
    - If not, here's the steps to fix it:
    - run `sudo usermod -aG docker $USER` and then reboot your PC.
    - You won't be able to run the needed Docker commands if this is not done.
7. Make sure that running `ls -la ~/.composer` shows your user instead of `root` for `.`.
    - If not, here's the steps to fix it:
    - Run `sudo chown -R $USER:$USER ~/.composer`.
    - You won't be able to store library authentication and Composer cache if this is not done.
8. Have the `make` extension installed.
9. Run `make setup` and you're done.

\[Optional\] Get access to private repositories you have access to on GitHub:

10. Generate an access token in GitHub with just the Repo permissions.
11. Run `make composer` and add `config --global github-oauth.github.com YOUR_GENERATED_TOKEN`.

###  Health Score

35

—

LowBetter than 79% of packages

Maintenance69

Regular maintenance activity

Popularity4

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 85.1% 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 ~29 days

Recently: every ~43 days

Total

7

Last Release

734d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/0b9d15511c1101a677b57fe76ccb6e4c449d49506767296458871e051b7201d2?d=identicon)[Rockylars](/maintainers/Rockylars)

---

Top Contributors

[![Rockylars](https://avatars.githubusercontent.com/u/21218585?v=4)](https://github.com/Rockylars "Rockylars (103 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (18 commits)")

---

Tags

packagephptests

###  Code Quality

TestsCodeception

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/rockylars-faker/health.svg)

```
[![Health](https://phpackages.com/badges/rockylars-faker/health.svg)](https://phpackages.com/packages/rockylars-faker)
```

###  Alternatives

[phpspec/prophecy

Highly opinionated mocking framework for PHP 5.3+

8.5k551.7M677](/packages/phpspec-prophecy)[infection/infection

Infection is a Mutation Testing framework for PHP. The mutation adequacy score can be used to measure the effectiveness of a test set in terms of its ability to detect faults.

2.2k26.2M1.8k](/packages/infection-infection)[vimeo/psalm

A static analysis tool for finding errors in PHP applications

5.8k77.5M6.7k](/packages/vimeo-psalm)[brianium/paratest

Parallel testing for PHP

2.5k118.8M752](/packages/brianium-paratest)[orchestra/testbench

Laravel Testing Helper for Packages Development

2.2k39.1M32.0k](/packages/orchestra-testbench)[pdepend/pdepend

Official version of pdepend to be handled with Composer

954110.9M806](/packages/pdepend-pdepend)

PHPackages © 2026

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