TestDummy makes the process of preparing factories (dummy data) for your integration tests as easy as possible

Related tags

Testing TestDummy
Overview

TestDummy Build Status SensioLabsInsight

TestDummy makes the process of preparing factories (dummy data) for your integration tests as easy as possible. As easy as...

Build a Post model with dummy attributes.

use Laracasts\TestDummy\Factory;

$post = Factory::build('Post');

If we then do $post->toArray(), this might return:

string(21) "The Title of the Post" ["author_id"]=> string(1) "5" ["body"]=> string(226) "Iusto qui optio et iste. Cumque aliquid et omnis enim. Nesciunt ad esse a reiciendis expedita quidem veritatis. Nostrum repellendus reiciendis distinctio amet sapiente. Eum molestias a recusandae modi aut et adipisci corrupti." ["publish_date"]=> string(19) "2014-03-02 11:05:48" }">
array(4) {
  ["title"]=>
  string(21) "The Title of the Post"
  ["author_id"]=>
  string(1) "5"
  ["body"]=>
  string(226) "Iusto qui optio et iste. Cumque aliquid et omnis enim. Nesciunt ad esse a reiciendis expedita quidem veritatis. Nostrum repellendus reiciendis distinctio amet sapiente. Eum molestias a recusandae modi aut et adipisci corrupti."
  ["publish_date"]=>
  string(19) "2014-03-02 11:05:48"
}

Build a post, but override the default title.

use Laracasts\TestDummy\Factory;

$post = Factory::build('Post', ['title' => 'Override Title']);

Again, when cast to an array...

string(14) "Override Title" ["author_id"]=> string(1) "5" ["body"]=> string(254) "In eos porro qui est rerum possimus voluptatem non. Repudiandae eaque nostrum eaque aut deleniti possimus quod minus. Molestiae commodi odit sunt dignissimos corrupti repudiandae quibusdam quo. Autem maxime tenetur autem corporis aut quis sint occaecati." ["publish_date"]=> string(19) "2013-06-24 10:01:30" }">
array(4) {
  ["title"]=>
  string(14) "Override Title"
  ["author_id"]=>
  string(1) "5"
  ["body"]=>
  string(254) "In eos porro qui est rerum possimus voluptatem non. Repudiandae eaque nostrum eaque aut deleniti possimus quod minus. Molestiae commodi odit sunt dignissimos corrupti repudiandae quibusdam quo. Autem maxime tenetur autem corporis aut quis sint occaecati."
  ["publish_date"]=>
  string(19) "2013-06-24 10:01:30"
}

Build an array of attributes for the model.

$post = Factory::attributesFor('Post');

The difference between build() and attributesFor() is that the former will return an instance of the given model type (such as Post). The latter will simply return an array of the generated attributes, which can be useful in some situations.

Build and persist a song entity.

use Laracasts\TestDummy\Factory;

$song = Factory::create('Song');

Create and persist a comment three times.

use Laracasts\TestDummy\Factory;

Factory::times(3)->create('Comment');

In effect, this will give you three rows in your comments table. If that table has relationships (such as an owning Post), those related rows will be created with dummy data as well.

Usage

Step 1: Install

Pull this package in through Composer, just like any other package.

"require-dev": {
    "laracasts/testdummy": "~2.0"
}

Step 2: Create a Factories File

TestDummy isn't magic. You need to describe the type of data that should be generated.

Within a tests/factories directory, you may create any number of PHP files that will automatically be loaded by TestDummy. Why don't you start with a generic tests/factories/factories.php file.

Each factory file you create will automatically have access to two variables:

  • $factory
  • $faker

$factory is the function that you'll use to define new sets of data, such as the makeup of a Post or Album.

$factory('Album', [
    'name' => 'Rock or Bust',
    'artist' => 'AC/DC'
]);

Think of this as your definition for any future generated albums - like when you do this:

use Laracasts\TestDummy\Factory;

$album = Factory::create('Album');

Faker

You probably won't want to hardcode strings for your various factories. It would be easier and faster to use random data. TestDummy pulls in the excellent Faker library to assist with this.

In fact, any files in your tests/factories/ directory will automatically have access to a $faker object that you may use. Here's an example:

$factory('Comment', [
    'body' => $faker->sentence
]);

Now, each time you generate a new comment, the body field will be set to a random sentence. Refer to the Faker documentation for a massive list of available fakes.

Relationships

If you wish, TestDummy can automatically generate your relationship models, as well. You just need to let TestDummy know the type of its associated model. TestDummy will then automatically build and save that relationship for you!

Using the Comment example from above, it stands to reason that a comment belongs to a user, right? Let's set that up:

$factory('Comment', [
    'user_id' => 'factory:User',
    'body' => $faker->sentence
]);

That's it! Notice the special syntax here: "factory:", followed by the name of the associated class/model.

To illustrate this with one more example, if a song belongs to an album, and an album belongs to an artist, then we can easily represent this:

$factory('App\Song', [
    'album_id' => 'factory:App\Album',
    'name' => $faker->sentence
]);

$factory('App\Album', [
    'artist_id' => 'factory:App\Artist',
    'name' => $faker->word
]);

$factory('App\Artist', [
    'name' => $faker->word
]);

So here's the cool thing: this will all work recursively. In translation, if you do...

use Laracasts\TestDummy\Factory;

$song = Factory::create('App\Song');

...then not only will TestDummy build and persist a song to the database, but it'll also do the same for the related album, and its related artist. Nifty!

Custom Factories

So far, you've learned how to generate data, using the name of the class, like App\User. However, sometimes, you'll want to define multiple types of users for the purposes of testing.

While it's true that you can use overrides, like this:

Factory::create('App\User', ['role' => 'admin']);

...if this is something that you'll be doing often, create a custom factory, like so:

// A generic factory for users...

$factory('App\User', [
    'username' => $faker->username,
    'password' => $faker->password,
    'role'     => 'member'
]);

// And a custom one for administrators

$factory('App\User', 'admin_user', [
    'username' => $faker->username,
    'password' => $faker->password,
    'role'     => 'admin'
]);

In the code snippet above, you're already familiar with the first example. For the second one, notice that we've added a "short name", or identifier for this special type of user factory. Now, whenever you want to quickly generate an admin user, you may do:

use Laracasts\TestDummy\Factory;

$adminUser = Factory::create('admin_user');

Defining with Closures

Alternatively, you may pass a closure as the second argument to the $factory method. This can be useful for situations where you need a bit more control over the values that you assign to each attribute. Here's an example:

$factory('App\Artist', function($faker) {
    $name = sprintf('Some Band Named %s', $faker->word);
    
    return [
        'name' => $name
    ];
});

Of course, just be sure to return an array from this closure. If you don't, an exception will be thrown.

Step 3: Setup

When testing against a database, it's recommended that each test works with the exact same database environment and structure. That way, you can protect yourself against false positives. An SQLite database (maybe even one in memory) is a good choice in these cases.

public function setUp()
{
    parent::setUp();

    Artisan::call('migrate');
}

Or, if a DB in memory isn't possible, to save a bit of time, a helper Laracasts\TestDummy\DbTestCase class is included with this package. If you extend it, before each test, your test DB will be migrated (if necessary), and all DB modifications will be channelled through a transaction, and then rolled back on tearDown. This will give you a speed boost, and ensure that all tests start with the same database structure.

use Laracasts\TestDummy\DbTestCase;

class ExampleTest extends DbTestCase {

    /** @test */
    function it_does_something()
    {
        // Before each test, your database will be rolled back
    }
}

Step 4: Write Your Tests

You're all set to go now. Start testing! Here's some code to get you started. Assuming that you have a Post and Comment model created...

use Laracasts\TestDummy\Factory;

$comment = Factory::create('Comment');

This will create and save both a Comment, as well as a Post record to the database.

Or, maybe you need to write a test to ensure that, if you have three songs with their respective lengths, when you call a getTotalLength method on the owning Album model, it will return the correct value. That's easy!

// create three songs, and explicitly set the length
Factory::times(3)->create('Song', ['length' => 200]);

$album = Album::first(); // this will be created once automatically.

$this->assertEquals(600, $album->getTotalLength());

Now, of course, just make sure that you've registered a definition for a Song and Album in one of your factory files, and you're good to go!

// tests/factories/factories.php

$factory('Song', [
  'album_id' => 'factory:Album',
  'name' => $faker->sentence
]);

$factory('Album', [
  'name' => $faker->sentence
]);

FAQ

How do I specify a different factories folder?

Easy. Before your tests run, add:

Factory::$factoriesPath = 'app/tests/factories';

Now, TestDummy will look for your registered factories in the app/tests/factories folder.

I want to control how my models are built and saved...

Okay, just create your own implementation of Laracasts\TestDummy\IsPersistable. This contract is composed of a few methods that you'll need to implement.

Once you have your implementation, before your tests run, add:

Factory::$databaseProvider = new MyCustomBuilder;

And that's it! Now, whenever you generate and save an entity, TestDummy will reference your custom implementation.

Comments
  • Many-to-many relationships?

    Many-to-many relationships?

    I know I can do the below example for a one-to-many relationship in TestDummy.

    Post:
      title: Hello World $string
      body: $text
      published_at: $date
      author_id:
        type: Author
    
    Author:
        name: John Doe $integer
    

    But how do I do a many-to-many relationship? This requires defining a pivot table, which I can't define in the fixtures.yml file.

    opened by ssfinney 17
  • 'Object of class Closure could not be converted to string' when mixing $factory and string in configuration

    'Object of class Closure could not be converted to string' when mixing $factory and string in configuration

    This is my first day working with TestDummy so let me know if there is a better way to accomplish what I'm trying.

    I'm looking to use TestDummy to generate random data, but to have a little bit of control over the output. For a Venue entity, instead of using $factory->sentence to get nonsense, I'd like to make use of Faker's abilities and get names like:

    Bobby's Bar Susan's Grille

    I can do this without a problem when using faker straight up

    echo "{$faker->firstName}'s {$faker->randomElement(['Bar', 'Grille'])};"
    

    but when I try using TestDummy I get the error

    'Object of class Closure could not be converted to string'
    

    I'm trying

    $factory('Venue', [
        'name'=>$faker->firstName . "'s "
    ]);
    

    but the concatenating makes the tool get angry.

    opened by mindofmicah 10
  • Issue creating multiple related resources

    Issue creating multiple related resources

    Using the following fixture, TestDummy will only create the first relation it finds, the subsequent relation(s) are skipped:

    
    Contact:
      first_name: $string
      last_name: $string
      email: $string@$string.com
      active: $boolean
      companies_id:
        type: Company
      user_id:
        type: User
    
    

    When executing TestDummy::create('Contact') the following error is generated

    
    Illuminate\Database\QueryException: 
    SQLSTATE[23000]: Integrity constraint violation: 19 contacts.user_id may not be NULL 
    (SQL: insert into "contacts" ("companies_id", "salutation", "first_name", "last_name", "email", "phone", "active", "updated_at", "created_at") 
    values (1, Prof., Sonia, Homenick, [email protected], 1-616-460-0515x5448, 1, 2014-10-31 18:02:35, 2014-10-31 18:02:35))
    
    
    opened by mikeerickson 9
  • Allow using closure for attributes

    Allow using closure for attributes

    The current method of passing in an array of attributes when defining a factory has a major limitation: you can only use scalars or single Faker calls unless you want to wrap them in complicated closures.

    This aims to fix that. Now, instead of an array of attributes you can pass $factory() a closure that returns the array. The closure is passed an instance of the Faker generator that isn't wrapped, so there's no wonky closure business to deal with when using Faker. This allows the factory to create more complicated fields, such as $faker->randomElement([ null, $faker->dateTime ]) or $faker->name . "'s" . $faker->randomElement([ 'Bar', 'Grille' ]) (as mentioned in #59).

    It also provides a way to conditionally fill fields based on data in other fields, which would currently be very cumbersome or impossible.

    Some notes:

    • #55 and #56 can be closed if this is merged as I included both bug fixes in this branch.
    • This fixes #59, or at least provides a way of doing what was desired.
    • I didn't much care for adding the Faker generator to the Builder class, but that class seemed like the best place to execute the closure since that's where it's built and where the attributes are retrieved. I liked the idea of adding a second $faker variable with some odd name to the factory loader that's passed to the closure via use () even less.
    opened by swekaj 8
  • Faker integration

    Faker integration

    I made the AttributeReplacer configurable and wrote a Faker implementation for it, including tests. Also added a method to quickly enable this implementation and updated the readme.

    Hope you like it.

    opened by jeroennoten 8
  • Is unique() supported?

    Is unique() supported?

    Hi, I’m not sure how to test if this a faker or TestDummy issue but I’m having trouble using the unique() feature of faker. My code looks like this:

    $factory('App\Product', [
        'sku' => $faker->unique()->ean13,
    ]);
    

    It doesn’t work: the seeder runs fine but the EAN generated are all the same.

    opened by redgluten 7
  • Faker not returning new randomized data

    Faker not returning new randomized data

    The following code throws constraint violations on email and username, but works when only 1 row is generated:

    $factory('App\User', function($faker) {
        $created = $faker->dateTimeBetween('-2 years', 'now');
    
        return [
            'username' => $faker->userName,
            'friendly_name' => $faker->firstName,
            'email' => $faker->safeEmail,
            'created_at' => $created,
            'last_login' => $faker->dateTimeBetween($created, 'now'),
        ];
    });
    

    Seems like it isn't generating a new value on each faker call...?

    bug 
    opened by gbrock 7
  • Bug reintroduced with recent commit

    Bug reintroduced with recent commit

    mergeFixtureWithOverrides was updated to use array_merge with the attributes. This was the original behavior in v1.0 and resulted in throwing Illuminate\Database\QueryException Unknown column errors. This bug was fixed in https://github.com/laracasts/TestDummy/pull/29 but it was recently changed back in https://github.com/laracasts/TestDummy/commit/e21fedc5ed56922549e6a4926b24be8f4b3f8ead to "Allow overriding fields not defined in a factory". For me, the better solution to that problem would be to just add the fields to the factory.

    This PR reverts back to the working version.

    fixes: https://github.com/laracasts/TestDummy/issues/77

    opened by devinfd 7
  • persist method was not passing attributes to relationships

    persist method was not passing attributes to relationships

    Two issues.

    1. $attributes variable was declared in the method and thus overriding anything passed in by the user.
    2. Attributes were not being passed to the persist method for any child/relationship factories and thus child attributes were not being overwritten.

    Thanks for the update!

    opened by devinfd 7
  • Overriding relation attributes

    Overriding relation attributes

    At the moment to set overrides on a relationship object I need to initiate both manually...

    $dummyBrand = TestDummy::create('Brand', [
        'slug' => 'the-brand-slug',
    ]);
    TestDummy::create('Trip', [
        'slug'     => 'the-trip-slug',
        'brand_id' => $dummyBrand->id,
    ]);
    

    In the example above.. I'd like to see a method of overriding Brand attributes via a Trip create()

    TestDummy::create('Trip', [
        'slug'     => 'the-trip-slug',
        'brand_id' => [
            'slug' => 'the-brand-slug',
        ],
    ]);
    

    I could probably implement this, but wanted to see if anyone else would benefit first!

    enhancement 
    opened by spamoom 6
  • get sub-arrays for 'attributesFor'

    get sub-arrays for 'attributesFor'

    this

    $factory('Album', [
        'name' => 'Rock or Bust',
        'artist' => 'AC/DC'
    ]);
    

    works fine for form

    <input type="text" name="name" />
    <input type="text" name="artist" />
    

    but not for this

    $factory('Album', [
        'name' => 'Rock or Bust',
        'artist' => ['name'=>'AC/DC','genre'=>'rock','email'=>'[email protected]']
    ]);
    
    <input name="name" />
    <input name="artist[name]" />
    <input name="artist[genre]" />
    <input name="artist[email]" />
    

    this PR handles these sub arrays in populating form html.

    opened by hardevine 5
  • fakerphp/faker downgraded when installing laracasts/testdummy

    fakerphp/faker downgraded when installing laracasts/testdummy

    I just created a new Laravel 8 project and then added laracasts/testdummy (which automatically installed version 2.5). When updating the dependencies, fakerphp/faker, which comes with Laravel, was downgraded from version 1.13.0 to version 1.9.2. This was reverted when I removed laracasts/testdummy from the composer.json and updated the dependencies again.

    Is the older faker version really necessary for TestDummy, or could the version number be easily changed?

    opened by enigmatic-user 0
  • Can't use array attributes

    Can't use array attributes

    I've been trying to wrap my head around this problem for some time and make my tests green. And then found this quite nasty and unwelcome "favor" that practically makes it impossible to use array values that are stored as JSON encoded strings:

                // It's possible that the called Faker method returned an array.
                // If that is the case, we'll implode it for the user.
    
                return is_array($attribute) ? implode(' ', $attribute) : $attribute;
    
    opened by Nekroido 0
  • Use factories for not Eloquent model

    Use factories for not Eloquent model

    I have a model which is not an Eloquent model. Still, I would like to have some integration tests.

    Is it possible to use the TestDummy package to create a factory for this type of models?

    opened by troccoli 8
  • Problem with attribute casting

    Problem with attribute casting

    It seems that if I set an array as value for a field that is specified in the $casts property in the model, it will be converted to a string. Is it supposed to work with attribute casting?

    opened by cdarken 0
Releases(2.5)
Mock HTTP requests on the server side in your PHP unit tests

HTTP Mock for PHP Mock HTTP requests on the server side in your PHP unit tests. HTTP Mock for PHP mocks the server side of an HTTP request to allow in

InterNations GmbH 386 Dec 27, 2022
Wraps your Pest suite in a Laravel application instance, allowing global use of the framework in tests.

Pest Larastrap Plugin This is currently a highly experimental project and is subject to large pre-release changes. Pest PHP is an awesome PHP testing

Luke Downing 3 Jan 6, 2022
Enforce consistent styling for your Pest PHP tests

A set of PHP CS rules for formatting Pest PHP tests.

Worksome 2 Mar 15, 2022
Prevent none-test output in your Pest tests.

Pest Plugin Silence Often, when writing tests, we echo and dump test code to debug and check everything is working correctly. It can be easy to forget

Worksome 5 Feb 23, 2022
vfsStream is a stream wrapper for a virtual file system that may be helpful in unit tests to mock the real file system. It can be used with any unit test framework, like PHPUnit or SimpleTest.

vfsStream vfsStream is a stream wrapper for a virtual file system that may be helpful in unit tests to mock the real file system. It can be used with

null 1.4k Dec 23, 2022
Some shorthand functions for skipping and focusing tests.

Pest Plugin: Shorthands This repository contains the Pest Plugin Shorthands. If you want to start testing your application with Pest, visit the main P

Thomas Le Duc 10 Jun 24, 2022
A PHP library for mocking date and time in tests

ClockMock Slope s.r.l. ClockMock provides a way for mocking the current timestamp used by PHP for \DateTime(Immutable) objects and date/time related f

Slope 44 Dec 7, 2022
Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slowness of constantly restarting the testing environment.

Magic Test for Laravel Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slownes

null 400 Jan 5, 2023
To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

Demin Yin 11 Sep 9, 2022
A tool to run migrations prior to running tests

cakephp-test-migrator A tool to run migrations prior to running tests The Migrator For CakePHP 3.x composer require --dev vierge-noire/cakephp-test-mi

Vierge Noire 11 Apr 29, 2022
Extension to use built-in PHP server on Behat tests

Extension to use built-in PHP server on Behat tests Instalation composer require libresign/behat-builtin-extension Configuration Add the extension to

LibreSign 2 Feb 21, 2022
This plugin adds basic HTTP requests functionality to Pest tests, using minicli/curly

Curly Pest Plugin This plugin adds basic HTTP requests functionality to Pest tests, using minicli/curly. Installation composer require minicli/pest-pl

minicli 16 Mar 24, 2022
Example repo for writing tests in Drupal (using DDEV)

Drupal Test Writing This is a test D9 site which can be used for practicing test writing and running.

David Stinemetze 13 Nov 14, 2022
Report high memory usage PHPUnit tests: Managed by opg-org-infra & Terraform

phpunit-memory-usage Report high memory usage PHPUnit tests: Managed by opg-org-infra & Terraform Configuration Add into the phpunit.xml extensions se

Ministry of Justice 2 Aug 4, 2022
Satisfy the Type APIs for the WordPress schema when running PHPUnit tests

Satisfy the Type APIs for the WordPress schema when running PHPUnit tests

GraphQL API 1 Apr 12, 2022
PHP Test Generator - A CLI tool which generates unit tests

This project make usages of PHPStan and PHPParser to generate test cases for a given PHP File.

Alexander Schranz 7 Dec 3, 2022
Magento PHPUnit Integration

Magento PHPUnit Integration Magento is a quite complex platform without built in unit test suite, so the code is not oriented on running tests over it

EcomDev B.V. 303 Dec 18, 2022
An effort to make testing PHP code as easy and fun as its JavaScript equivalent

An effort to make testing PHP code as easy and fun as its JavaScript equivalent when using the excellent Jasmine, from which syntax and general usage is shamelessly borrowed.

Johan Stenqvist 24 Apr 22, 2022