2

I'm looking into using DataFactory's in Codeception for seeding of data, and for use in our acceptance tests. In the documentation there's mention of 2 approaches, one using the helper file and one using factories files.

We load both options using this snippet from our acceptance.suite.yml

class_name: AcceptanceTester
modules:
    enabled:
        - Db
        - WebDriver
        - \Helper\Acceptance
        - Doctrine2:
            connection_callback: getEntityManager
        - DataFactory:
            factories: tests/_support/factories
            depends: Doctrine2
        - \Helper\Factory

Both of the options seem to load correctly. As per the documentation I can then define factories like this, which will allow interaction with Doctrine.

// tests/_support/Helper/Factory.php
class Factory extends Module
{

    /**
     * @param array $settings
     * @throws \League\FactoryMuffin\Exceptions\DefinitionAlreadyDefinedException
     * @throws \Codeception\Exception\ModuleException
     */
    public function _beforeSuite($settings = [])
    {
        /** @var Module\DataFactory $factory */
        $factory = $this->getModule('DataFactory');

        /** @var EntityManager $em */
        $em = $this->getModule('Doctrine2')->_getEntityManager();

        $factory->_define(User::class,[
            // generate random user name
            'name' => Faker::name(),
        ]);
        parent::_beforeSuite($settings);
    }
}

As per the other option, I can also create factories by loading all files from within tests/_support/factories, such as below:

// tests/_support/factories/seed.php
use League\FactoryMuffin\Faker\Faker;

/** @var \League\FactoryMuffin\FactoryMuffin $fm */
$user = $fm->create(User::class);
dd($user);

However, the seed.php version cannot seem to share the Factory, and errors with:

The model definition 'User' is undefined.

I wondered if maybe this could be solved by moving the Factory.php logic into the initialize() method but this seems to be called before FactoryMuffin has been initiliazed.

The documentation for this with codeception seems a bit sparse, and the FactoryMuffin docs, while better, don't cover Codeception integration. Just trying to work out if i'm missing something, or I just need to repeat the code in each place if I want to use both files/methods.

robjmills
  • 18,438
  • 15
  • 77
  • 121

1 Answers1

0

This is an old question and technology moves fast so the documentation has likely changed since this was originally asked but I'll make an attempt in case anyone else stumbles across it like I did.

You're using the DataFactory module which is great as it comes with the integration for Codeception out of the box. The two methods you've described are actually ways of integrating DataFactory with your data. By creating factory files, you've given DataFactory a means of generating data. But what if you have some data already in the database that you'd like to use in your tests as well? That's where you would use the Helper class. According to the DataFactory Module docs:

In cases you want to use data from database inside your factory definitions you can define them in Helper. For instance, if you use Doctrine, this allows you to access EntityManager inside a definition.

As for your issue of seed.php not finding the User model, you need to specify it according to the definition given in your factory. For example, if your factory file looks similar to this

<?php
use League\FactoryMuffin\Faker\Facade as Faker;
$fm->define('app\models\User')->setDefinitions([
        'name' => Faker::name(),
        ... // the rest of your properties here
    ]);

Then seed.php would look like

// tests/_support/factories/seed.php
use League\FactoryMuffin\Faker\Faker;

$user = $fm->create('app\models\User');

Once you have the DataFactory module installed and configured, you can simply call it within the appropriate testing suite via have, haveMultiple, or make. See the Codeception Docs