Unit Testing your closure methods with PHP

miguel costa
2 min readMay 2, 2021

Today, I am happy to share with you guys with a practical example how to test the business logic of the Closures inside our methods, imagine that you have a method like the next one on your PHP Class:

public function delete(): Timestamp
{
$query = $this;
return $this->connection->runTransaction(function(Transaction $t) use($query) {
$t->executeUpdate($query->grammar->compileDelete($query), [
'parameters' => $query->getBindings()
]);
return $t->commit();
});
}

Since we are running another object inside our closure, we will need to mock this one beyond the Connection class on the example, at least for the methods executeUpdate and commit, to do that we can follow the next example:

public function testReturnTimestampWhenCallingDeleteMethodProperly()
{
$date = new DateTimeImmutable(date('Y-m-d'));
$timestamp = new Timestamp($date);
$connection = Mockery::mock(ConnectionI::class); $connection->shouldReceive('runTransaction')->once()->with(
Mockery::on(function(Closure $transaction) use($timestamp) {
$mockTransaction = Mockery::mock(TransactionI::class);
$mockTransaction->shouldReceive('executeUpdate')->andReturn(1)->once();
$mockTransaction->shouldReceive('commit')->andReturn($timestamp)->once();
$this->assertSame($timestamp, $transaction($mockTransaction)); return true;
})
)->andReturn($timestamp);
$this->assertEquals($timestamp, $this->builder->delete());
}

As you can see, we are mocking the objects inside the closure, this specific example should return a DateTimeImmutable object, after the shouldReceive, we can use the method with to emulate our closure and test whatever we need to do inside that.

Hope this example can save you a little of your time :)

--

--

miguel costa

Software Developer, trying to learn more every day.