Creating User Data From Behat Background - Part 2

This video is available to view for members only.

Click here to Join!

Already a member?

Login


Following on from the previous video, in this part we will write the code that populates the thereAreUsersWithTheFollowingDetails function in our UserSetupContext.

By the end of this video, we should have the following in our UserSetupContext:

<?php

// src/AppBundle/Features/Context/UserSetupContext.php

namespace AppBundle\Features\Context;

use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;
use Behat\Gherkin\Node\TableNode;
use Doctrine\ORM\EntityManagerInterface;
use FOS\UserBundle\Model\UserManagerInterface;

class UserSetupContext implements Context, SnippetAcceptingContext
{
    /**
     * @var UserManagerInterface
     */
    private $userManager;
    /**
     * @var EntityManagerInterface
     */
    private $em;

    public function __construct(UserManagerInterface $userManager, EntityManagerInterface $em)
    {
        $this->userManager = $userManager;
        $this->em = $em;
    }

    /**
     * @Given there are Users with the following details:
     */
    public function thereAreUsersWithTheFollowingDetails(TableNode $users)
    {
        foreach ($users->getColumnsHash() as $key => $val) {

            $user = $this->userManager->createUser();

            $user->setEnabled(true);
            $user->setUsername($val['username']);
            $user->setEmail($val['email']);
            $user->setPlainPassword($val['password']);

            $this->userManager->updateUser($user);


            $qb = $this->em->createQueryBuilder();

            $query = $qb->update('AppBundle:User', 'u')
                ->set('u.id', $qb->expr()->literal($val['uid']))
                ->where('u.username = :username')
                ->andWhere('u.email = :email')
                ->setParameters([
                    'username' => $val['username'],
                    'email'    => $val['email']
                ])
                ->getQuery();

            $query->execute();
        }
    }
}

Let's walk through what's happening here in a little more depth.

We injected the UserManager, which is the user manager created for us when we configured FOSUserBundle. We also inject the 'standard' Doctrine entity manager so we can update this user outside the scope of FOSUserBundle's normal operations.

Behat has the concept of tables of data:

  Background:
    Given there are Users with the following details:
    | uid | username | email          | password |
    | u1  | peter    | peter@test.com | testpass |
    | u2  | john     | john@test.org  | johnpass |

This data is passed to our function as a TableNode which we are calling $users, simply because that's what this table node represents.

I have covered Table Nodes in more detail on the blog, so be sure to read up on that post if you are unsure on the concept of Table Nodes, or what sort of data they provide.

The first row in a Table Node is considered to contain the titles of the data. In our case, this would be uid, username, email, and password. These values will be used as keys in our array, which we will use when looping through our data.

Once inside our loop, the standard procedure of creating a User with FOSUserBundle is followed as normal.

$user = $this->userManager->createUser();

$user->setEnabled(true);
$user->setUsername($val['username']);
$user->setEmail($val['email']);
$user->setPlainPassword($val['password']);

$this->userManager->updateUser($user);

We create a User using the user manager. This creates an 'empty' user, which we then populate - and importantly, enable. We could set the value of enabled to also be passed in via the table, but for the purposes of this test feature, we always expect our Users to be enabled.

Be sure to set the plain password here, rather than simply the password - if unsure on this, be sure to watch the FOSUserBundle tutorial course here at CodeReviewVideos.

Changing The User ID

Where this step gets more interesting is in we are changing the User's ID.

First, we must have saved the User to the database. We do this in the $this->userManager->updateUser($user); line.

At this point, the user will have received an automatically generated ID - something long and -crazy- unique. This is great in the real world, but not so good for us in test.

In test, we want to control the ID so we can then use it in subsequent stages for relationships, and also for access via our API end points. If we don't control this ID, the rest of our testing becomes impossible.

To change the ID, we need to write a standard Doctrine update statement:

$qb = $this->em->createQueryBuilder();

$query = $qb->update('AppBundle:User', 'u')
    ->set('u.id', $qb->expr()->literal($val['uid']))
    ->where('u.username = :username')
    ->andWhere('u.email = :email')
    ->setParameters([
        'username' => $val['username'],
        'email'    => $val['email']
    ])
    ->getQuery();

$query->execute();

Hopefully nothing new here, but simply finding the user by their username and email address, and updating their id to the one we want it to be.

We use the $qb->expr()->literal($val['uid']) syntax which is rather unusual looking, so we don't need to pass in a parameter. You are free to do this how you like, but this is the way I tend to do it.

After this, your feature should run and populate the fos_users table with the expected rows, with their expected IDs.

From here we can ramp up the speed somewhat and start adding in more entity creation steps without reviewing them in quite so much detail.


Code For This Course

Get the code for this course.

Share This Episode

If you have found this video helpful, please consider sharing. I really appreciate it.


Episodes in this series

# Title Duration
1 Project Introduction 17:13
2 Setting Up Our Development Environment 05:08
3 Installing Symfony 3, Behat, and more 13:53
4 User Feature - Part 1 17:47
5 User Feature - Part 2 07:51
6 Talking English To Your Computer 11:05
7 Teaching Your Database To Forget 07:42
8 Creating User Data From Behat Background - Part 1 14:44
9 Creating User Data From Behat Background - Part 2 11:33
10 Creating A Custom RestApiContext 17:44
11 Our First Passing Behat User Scenario 12:01
12 Our Next Passing Step 13:10
13 Securing Our User Endpoint - Part 1 17:17
14 Securing Our User Endpoint - Part 2 24:27
15 Securing Our User Endpoint - Part 3 24:47
16 Log In To A Symfony API With JWTs (LexikJWTAuthenticationBundle) 11:02
17 Implementing PATCH for Users 18:17
18 Improving our API User Experience 13:59
19 GET a Collection of Accounts 12:15
20 POSTing in New Accounts 14:34
21 PUT and PATCH for Accounts 12:14
22 How To DELETE Existing Accounts 05:11
23 File Feature Overview 11:40
24 File - Using Existing Resources as Boilerplate 15:17
25 File POST 14:53
26 Fixing A Bug In POST Guided By Behat 12:50
27 Wrapping Up With File DELETE 07:47