Home > Blockchain >  PHP Unit Test Closure functions
PHP Unit Test Closure functions

Time:06-05

I was performing unit test in my application, and some of the functions include closure functions like below:

<?php

namespace JobProgress\Transformers;
use League\Fractal\TransformerAbstract;
class CustomersTransformer extends TransformerAbstract {
    
    public function includesCreatedBy($customer) {
         $user = $customer->createdBy;
         if($user) {
              return $this->item($user, function($user){
                 \Log::info('unit test');
                  return [
                    'id'               => (int)$user->id,
                    'first_name'       => $user->first_name,
                    'last_name'        => $user->last_name,
                    'full_name'        => $user->full_name,
                    'full_name_mobile' => $user->full_name_mobile,
                    'company_name'     => $user->company_name,
                 ];
             });
         }
    }
}

Note : I have extended TransformerAbstract class of Fractal and using the item function as $this->item from the TransformerAbstract class.

Here is how i am executing my test:

public function testIncludeDeletedBy() {
        $customer = factory(Customer::class)->create();
        $include = $this->transformer->includesCreatedBy($customer);
        $object = $include->getData()->first();
        $this->assertInstanceOf(User::class, $object);
}

My unit test is not executing the code that i have written in closure function. Like as i have mentioned in above code, i have added some logs but my unit test is not executing that portion of the code.

Can anyone please help me

CodePudding user response:

This might be related to the implementation detail of the $this->item() method. You may expect the closure to be executed while as we can see, the closure only needs to be parsed and then passed to the method as a parameter.

The code shows nothing that it is actually executed and therefore you should not expect this to be as it is an implementation detail not under your test.

You could de-anonymize the closure and call it directly to be able to test it as a unit.

So you have one test for the if-clause in the existing method and one test which allows you to run (not only parse) the code you currently have as an anonymous function / closure.

This is sometimes called a test-point and can bring you up speed. The smaller the units you have are, the easier it is to test them.

<?php

namespace JobProgress\Transformers;
use League\Fractal\TransformerAbstract;
class CustomersTransformer extends TransformerAbstract {
    
    public function includesCreatedBy($customer) {
         $user = $customer->createdBy;
         if($user) {
              return $this->item($user, $this->transformImplementation(...));
         }
    }

    public function transformImplementation(object $user) {
        \Log::info('unit test');
        return [
            'id'               => (int)$user->id,
            'first_name'       => $user->first_name,
            'last_name'        => $user->last_name,
            'full_name'        => $user->full_name,
            'full_name_mobile' => $user->full_name_mobile,
            'company_name'     => $user->company_name,
        ];
    }
}

For the three dots (...), this is PHP 8.1 syntax, compare PHP RFC: First-class callable syntax for alternative PHP syntax before 8.1 for callables, e.g.:

Closure::fromCallable([$this, 'transformImplementation'])
  • Related