Skip to content

Instantly share code, notes, and snippets.

@jakzal
Last active April 26, 2023 20:37
Show Gist options
  • Save jakzal/d601b419187e1d0db9af to your computer and use it in GitHub Desktop.
Save jakzal/d601b419187e1d0db9af to your computer and use it in GitHub Desktop.
Test data builder
<?php
$defaultUser = (new UserBuilder())->build();
$justRegisteredUser = UserBuilder::justRegistered()->withUsername('Anonymous')->build();
$complexUser = (new UserBuilder())
->withUsername('Test user')
->withEmail('test@example.com')
->build();
$user = (new UserBuilder())
->with(['username' => 'Test user'])
->build();
<?php
namespace Acme\Builder;
class TestDataBuilder
{
/**
* @var array
*/
protected $defauts = [];
/**
* @var array
*/
protected $data = [];
/**
* @return object
*/
public function build()
{
$data = array_merge($this->defaults, $this->data);
$entity = $this->instantiate();
foreach ($data as $field => $value) {
$this->setObjectProperty($entity, $field, $value);
}
return $entity;
}
/**
* @param string $name
* @param array $arguments
*
* @return $this
*
* @throws \BadMethodCallException in case method is not supported
*/
public function __call($name, $arguments)
{
if (0 === strpos($name, 'with') && 1 === count($arguments)) {
$name = lcfirst(str_replace('with', '', $name));
return $this->withProperty($name, $arguments[0]);
}
throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s', static::class, $name));
}
/**
* @param array $data
*
* @return $this
*/
public function with(array $data)
{
foreach ($data as $property => $value) {
$this->data[$property] = $value;
}
return $this;
}
/**
* @param string $name
* @param mixed $value
*
* @return $this
*/
protected function withProperty($name, $value)
{
$this->data[$name] = $value;
return $this;
}
/**
* @param object $object
* @param string $name
* @param mixed $value
*/
protected function setObjectProperty($object, $name, $value)
{
$property = new \ReflectionProperty(static::DATA_CLASS, $name);
$property->setAccessible(true);
$property->setValue($object, $value);
}
/**
* @return object
*
* @throws \RuntimeException in case the DATA_CLASS constant hasn't been set
*/
protected function instantiate()
{
if (!defined('static::DATA_CLASS')) {
throw new \RuntimeException(sprintf('Define DATA_CLASS constant for the %s', get_class($this)));
}
$class = static::DATA_CLASS;
return new $class();
}
}
<?php
namespace Acme\Builder;
use Acme\User;
class UserBuilder extends TestDataBuilder
{
const DATA_CLASS = User::class;
protected $defaults = [
'username' => 'Kuba',
'email' => 'kuba@example.com',
'registeredAt' => null,
'active' => true
];
public function __construct()
{
$this->defaults['registeredAt'] = new \DateTime('-1year');
}
static public function justRegistered()
{
return (new self())
->withRegisteredAt(new \DateTime('now'));
}
public function withRegisteredAt(\DateTime $registeredAt)
{
return $this->withProperty('registeredAt', $registeredAt);
}
}
@HajoAhoMantila
Copy link

This is good stuff! Could you add a license to it? Otherwise it's difficult to use it in other projects. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment