tijmen-wierenga/bogus
Bogus is a small Laravel/PHP package for generating fake or placeholder data, handy for testing, seeding, and prototyping. It offers simple helpers to produce bogus values quickly without pulling in a heavier faker library.
Bogus is a small, framework-agnostic dummy-data factory — conceptually the same idea as Laravel's model factories (define, make, create, states), but it predates Laravel 8's class-based factories and was written to be usable outside Eloquent as well.
Install as a dev dependency — it is a test/seed-time tool, never a runtime one:
composer require --dev tijmen-wierenga/bogus
Check package discovery. If you are on Laravel 5.5+ the service provider and Bogus facade should be auto-registered. On anything older (or if the facade alias is missing), add the provider to config/app.php providers and the alias to aliases manually. This is the single most common reason a first Bogus::define(...) call fails with a "class not found" or container binding error.
Look first at src/Factory.php and the service provider, not the README. The README on a 3-star archived repo is thin and the method names (define, of, times, make, create, state) are close enough to Laravel's that you'll assume behaviour that isn't there. The provider tells you whether the factory is a singleton (state leaks between tests) or bound per-resolution.
First use case: define one factory in a TestCase setUp() or a dedicated service provider and call make() on a plain object. Do not start with create() on an Eloquent model — verify the in-memory path works before you involve the database.
Bogus::define(User::class, function ($faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
];
});
$user = Bogus::of(User::class)->make();
Centralise definitions. Put every define() call in one place — a DatabaseFactoryServiceProvider registered only in the testing environment, or a trait on your base TestCase. Duplicating definitions across test classes is how you get two tests that disagree about what a "valid" user looks like.
make() for unit tests, create() for integration tests. make() returns a populated in-memory object; create() persists. Most test suites only need create() in feature tests that exercise the database, and reaching for it everywhere is the fastest way to make a suite slow.
Overrides beat states for one-offs. Pass an array of overrides when a single test needs one changed attribute; reserve named states for variants that recur (e.g. ->state('admin')). If you find yourself overriding four-plus keys, you want a new state instead.
Collections via times(). Batch with ->times(10)->make() rather than a for loop — it keeps the faker sequence and any unique counters coherent, and it is where the package is actually more ergonomic than hand-rolling.
Compose for associations. Return a nested closure from a definition so a Post factory can lazily create its User. Keep it lazy — a factory that eagerly builds associations will explode the cost of a ->times(100) call.
Expose it behind your own helper. Wrap the facade in a small $this->factory(User::class, [...]) helper on your base test case. That one indirection is what makes the eventual migration to User::factory() a one-file change rather than a repository-wide find-and-replace.
Non-Eloquent use is the real niche. The reason to tolerate the rough edges is that Bogus will happily define factories for DTOs, value objects, or API payloads that have no database table. Laravel's factories push you toward Eloquent; this one doesn't.
composer update to eventually break it via a transitive Faker constraint. Pin the version explicitly and plan the exit.fzaninotto/faker, which is abandoned in favour of fakerphp/faker. If Composer refuses to resolve, you are looking at a fork-the-package situation, not a config tweak.setUp (idempotently) rather than per-test, and be suspicious of any test that passes alone but fails in suite.create() + unique() + transactions. $faker->unique() only guarantees uniqueness within the current faker instance. Under RefreshDatabase with rolled-back transactions, a unique counter that resets per test can still collide with rows a seeder left behind — seed with create() after truncation, not before.$faker->seed(1234)) so you can replay it. Without that, a flaky test on dummy data is genuinely undebuggable.How can I help you explore Laravel packages today?