kfirba's avatar
Level 50

How to test commands as the domain layer

Hello.

I really like using Behat with ubiquitous language as I can then run the features against a DomainContext and a UserInterfaceContext. However, I find it quite hard to test my commands.

If I'm not using a command and just for example a repository I would do something like this in my test step:

protected $repo;

// maybe there is a way to do it more elegantly?
public function __construct() {
    $this->repo = app('FooRepository');
}

// in my step
$this->repo->bar($args);

However, when it comes down to commands, how should I test it? My command itself will take advantage of the repository so I need to somehow trigger my command or my underlying code?

If my command's handle method is:

public function handle(FooRepository $repo)
{
    $repo->bar($this->args);
}

How would I approach it in my test?

protected $dispatcher;
public function __constrcut()
{
    $this->dispatcher = app('Illuminate\Contracts\Bus\Dispatcher');
}

// in my step
$this->dispatcher->dispatchFrom(FooCommand::class, $args)

I really feel that there is a much better way to do this but I'm missing it.

Please share with me how should I test that.

P.S. In my first example w/o commands I resolved a repository from the IoC Container, do you think there is a more elegant way to do it? Or for each repository my context may need I will have to resolve it out of the IoC container which can very quickly become cluttered :/

0 likes
5 replies
HRcc's avatar

Generally I just dispatch the command (e.g. RegisterCustomerCommand) and then I verify if the user is created, check assigned roles,... I consider these tests to be functional/acceptance. In other words why when I want to test for registering a customer, what does it mean to me? I expect the user to be present in the DB, I expect the user to have a customer role, ... and I'm not interested how the command handler does it internally.

kfirba's avatar
Level 50

@HRcc If I get you right, you would go with my suggested solution:

protected $dispatcher;
public function __constrcut()
{
    $this->dispatcher = app('Illuminate\Contracts\Bus\Dispatcher');
}

// in my step
$this->dispatcher->dispatchFrom(FooCommand::class, $args)

Do you maybe know any better way to do that? I just don't like the idea that each repository I will need for my test will need to be manually set in the construct method of my context.

Any other ideas are also welcome.

HRcc's avatar

Actually, you don't need to make repositories in the constructor of the context. They are encapsulated by the command handler itself. You'll need to instantiate them only if you need them to verify the correct execution of the command. (Or you can use eloquent directly)

kfirba's avatar
Level 50

@HRcc I mentioned repositories as for when I don't use commands and use the repositories directly. I just don't like this solution of the constructor. Guess I will have to use it though.

Please or to participate in this conversation.