Unit test UploadedFile.php in PHPSpec - php

I am trying to test a data transfer object class which constructs with Symfony\Component\HttpFoundation\File\UploadedFile.php class in Laravel. I've had no luck testing this implementation in PHPSpec. Here is what I have so far:
Test
public function let($event_id)
{
$prophet = new Prophet;
$prophecy = $prophet->prophesize();
$prophecy->willBeConstructedWith(array('path', 'name'));
$prophecy->willExtend('Symfony\Component\HttpFoundation\File\UploadedFile');
$attendee_list = $prophecy->reveal();
$this->beConstructedWith($event_id, $attendee_list);
}
public function it_is_initializable()
{
$this->shouldHaveType('Captix\Attendees\ImportAttendeesCommand');
}
Class
class ImportAttendeesCommand
{
/**
* Event primary key
* #var $event_id
*/
protected $event_id;
/**
* CSV file
* #var $attendee_list
*/
protected $attendee_list;
/**
* Constructor for ImportAttendeesCommand
*/
public function __construct($event_id, UploadedFile $attendee_list)
{
$this->event_id = $event_id;
$this->attendee_list = $attendee_list;
}
}
Result
2 -_-__,------,
0 -_-__| /\_/\
0 -_-_^|__( o .o)
1 -_-_ "" ""
Captix/Attendees/ImportAttendeesCommand
38 ! it is initializable
exception [exc:Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException("The file "path" does not exist")] has been thrown.
0 vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/File.php:41
throw new Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException("The file "path" does not ...")
1 vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/UploadedFile.php:100
Symfony\Component\HttpFoundation\File\File->__construct("path", true)
2 vendor/phpspec/prophecy/src/Prophecy/Doubler/Generator/ClassCreator.php(49) : eval()'d code:6
Symfony\Component\HttpFoundation\File\UploadedFile->__construct("path", "name", null, null, null, null)
3 [internal]
Double\Symfony\Component\HttpFoundation\File\UploadedFile\P4->__construct("path", "name")
4 vendor/phpspec/prophecy/src/Prophecy/Doubler/Doubler.php:109
ReflectionClass->newInstanceArgs([array:2])
5 vendor/phpspec/prophecy/src/Prophecy/Doubler/LazyDouble.php:119
Prophecy\Doubler\Doubler->double([obj:ReflectionClass], [array:0], [array:2])
6 vendor/phpspec/prophecy/src/Prophecy/Prophecy/ObjectProphecy.php:114
Prophecy\Doubler\LazyDouble->getInstance()
7 app/Spec/Captix/Attendees/ImportAttendeesCommandSpec.php:33
Prophecy\Prophecy\ObjectProphecy->reveal()
8 [internal]
Spec\Captix\Attendees\ImportAttendeesCommandSpec->let([obj:PhpSpec\Wrapper\Collaborator])
3 examples (2 passed, 1 broken)
119ms
I've tried several ways to test this, using Mockery, Prohpecy, stdClass, nothing seems to be working. Any help on this would be much appreciated. I am welcome to any implementation of this test. Thanks to all in advance.

Create an interface:
interface UploadedFileInterface
{}
Create class that implements this interface and extends Symfony class.
class MyUploadedFile extends UploadedFile implements UploadedFileInterface
{}
Change constructor in your command:
public function __construct($event_id, UploadedFileInterface $attendee_list)
{
$this->event_id = $event_id;
$this->attendee_list = $attendee_list;
}
Now You can easily test your class in isolation:
public function let($event_id, UploadedFileInterface $attendeeList)
{
$this->beConstructedWith($event_id, $attendeeList);
}
And if some day you will have to switch from Symfonys UploadedFile to another implementation, the only place that you will have to change will be MyUploadedFile class.

I had the same issue using prophecy to mock the UploadedFile so I submitted an issue for feedback (https://github.com/phpspec/prophecy/issues/184).
The solution is 'do not mock what you do not own'. I'm not sure yet how you would put that into practice, but thought you might be interested.

Related

PHP Unit mocked objects types

What is the correct way of setting a type for mocked objects?
Example code:
/**
* #dataProvider getTestDataProvider
* #throws Exception
*/
public function testExampleData(
Request $request,
Response $expected,
SomeClass $someClassMock
): void {
$result = $someClassMock->getData($request);
$this->assertEquals($expected, $result);
}
In this example the type of $someClassMock is class SomeClass. Also there is a type called MockObject which is also working properly, but it messes up the autocompletion of functions inside that class.
Which types should I use on these mocked objects? Real object class or MockObject?
What I do to make sure the auto completion works for the mocked class as well as the MockObject, is tell php that it can be either class. This adds the auto complete for both and also makes it quite understandable for anyone reading the code that it is a mock and what object it is mocking.
In your case it would look like this:
/**
* #dataProvider getTestDataProvider
* #throws Exception
*/
public function testExampleData(
Request $request,
Response $expected,
SomeClass|MockObject $someClassMock // <-- Change made here
): void {
$result = $someClassMock->getData($request);
$this->assertEquals($expected, $result);
}
You will still be passing in the MockObject, but your IDE will not complain about any unknown functions.
EDIT: To make it work with PHP versions before 8, I would suggest something like this (minimal example):
class ExampleTest extends TestCase
{
private someClass | MockObject $someClassMock;
public function setUp(): void
{
$this->someClassMock = $this->createMock(SomeClass::Class);
}
public function testMe()
{
$this->someClassMock->expects($this->once())->method('getData')->willReturn('someStuff');
}
}
In this scenario the variable $someClassMock is declared as both types and you can use it throughout your test with autocompletion for both of them. This should also work with your data provider although you might have to rewrite it slightly. I didn't include it in my example to keep it simple.

PHPUNIT Mocking method to accept any parameter

I use simple-phpunit from phpunit/phpunit-bridge by and with Symfony here.
I have a class A, that I desire to test, which uses a class B method in it.
While mocking the B and it's method I realise it is called multiple time and with multiple parameters : a class name and a integer.
I use returnValueMap() for this but have a problem : PHPUNIT seem to require that I precisely set the parameters, to their exact value when the method shall be called.
I can set the class name ( there are a given possible number fo them , so I can set them manually) but the given integer is arbitrary ( and the method is called in a loop ) , therefore I cannot set it precisely.
Is it possible to tell PHPUNIT to accept any parameter to this function ?
Like a anyParameter() method ( that I did not find after scouring the TestCase file ).
If I set the Integer parameter to a fixed value in the test and the class method, the test pass ( but of course I can't set the Integer as a fixed value in the class method ).
class ToBeTested{
public $objectB;
public function functionToTest($dataList){
......
$objectB=new ObjectB();
foreach($dataList as $data){
$className=$data['className'];
$integerNeeded=$data['integer'];
//Here if $inetegerNeeded is not the exact value set in the Mock
//$result will be null
$result=$this->objectB->doSomething($className,$integerNeeded);
if($result == null) throw new \Excpetion(" Object is null");
}
.....
}
}
class UnitTest extends TestCase{
/**
$generatedDataList comes from a DataProvider
with some varied and exotic data close to real use cases
**/
public function testFunction($generatedDataList)
{
$mockOfObjectB= $this->getMockBuilder(ObjectB::class)
->getMock();
/**
Here I'd like to use $this->anyParameter() or something that'd work that way
If I set this to a fixed value here and in the functionToTest() method it passes
**/
$anyInteger=-1;
$dataReferenceMap= [
['ClassNameA',$anyInteger,new MockObject()],
['ClassNameB',$anyInteger,new MockObject()],
['ClassNameC',$anyInteger,new MockObject()],
];
$mockOfObjectB
->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($dataReferenceMap));
$objectToTest = new ToBeTested();
$objectToTest->objectB=$mockOfObjectB;
//DO THE TESTING - will because of the parameter Fail
$objectToTest->functionToTest($generatedDataList);
}
}
}
Might I also be wrongly returnValueMap() ?
It's quite new to me and I think the docs on it are pretty scarce and don't explain really well how to use it.
I would go with willReturnCallback. Here is the example (checked with phpunit 8.1)
<?php
declare(strict_types = 1);
use PHPUnit\Framework\TestCase;
final class SomeTest extends TestCase
{
public function testSome()
{
$mock = $this
->getMockBuilder(\stdClass::class)
->setMethods(['doSomething'])
->getMock();
$mock->method('doSomething')
->willReturnCallback(
function (string $classname, int $int) {
$map = [
'ClassNameA' => 123,
'ClassNameB' => 345,
// ...
];
return $map[$classname];
}
);
$this->assertSame(123, $mock->doSomething('ClassNameA', 1));
$this->assertSame(123, $mock->doSomething('ClassNameA', 1111111));
$this->assertSame(345, $mock->doSomething('ClassNameB', 13456));
$this->assertSame(345, $mock->doSomething('ClassNameB', 999999));
}
}
It is a shortcut for ->will($this->returnCallback(...)). The doc

Is there any way to execute data provider fuction after setupBeforeClass?

I have a unit test class in which I want to instantiate a object from another class in order to that I used setUpBeforeClass() fixtures of phpunit. So if I will use that recently instantiated object directly in test function then its working fine.
If i'll use this object into another function which had been created for data providers. So that object sets to null cause providers always execute first.
Is there a way to call dataProviders just before the test runs, instead?
require_once('Dashboard.php');
Class Someclass extends PHPUnit_Framework_TestCase {
protected static $_dashboard;
public static function setUpBeforeClass()
{
self::$_dashboard = new Dashboard();
self::$_dashboard->set_class_type('Member');
}
/**
* Test Org Thumb Image Existense
* param org profile image : array
* #dataProvider getOrgProfileImages
*/
public function testFieldValidation($a,$b){
//If I call that object function here it will give the result.
//$members = self::$_dashboard->get_members();
//var_dump($members); Printing result as expected
$this->assertTrue(true);
}
public function getOrgProfileImages() : array {
//var_dump(self::$_dashboard);
$members = self::$_dashboard->get_members();
$tmp_array = ['2','2'];
return $tmp_array;
}
public static function tearDownAfterClass()
{
self::$_dashboard = null;
}
}
Error:
The data provider specified for Someclass::testFieldValidation is invalid.
Call to a member function get_members() on null
Please help to mitigate this issue.
Note: since I don't have the source of your Dashboard class, I'm using a random number in the examples below instead
Providers are invoked before any tests are run (and before any hooks, including beforeClass have a chance to run). By far the easiest way to achieve what you're after is to populate that static property on the class load:
use PHPUnit\Framework\TestCase;
/** #runTestsInSeparateProcesses enabled */
class SomeTest extends TestCase
{
public static $_rand = null;
public function provider()
{
$rand = self::$_rand;
var_dump(__METHOD__, getmypid(), 'provided rand', $rand);
return ['rand' => [$rand]];
}
/** #dataProvider provider */
public function testSomething($rand)
{
$this->expectNotToPerformAssertions();
var_dump(__METHOD__, getmypid(), 'tested with', $rand);
}
/** #dataProvider provider */
public function testSomethingElse($rand)
{
$this->expectNotToPerformAssertions();
var_dump(__METHOD__, getmypid(), 'tested with', $rand);
}
}
// this runs before anything happens to the test case class
// even before providers are invoked
SomeTest::$_rand = rand();
Or you could instantiate you dashboard in the provider itself, on the first call:
public function provider()
{
// Instantiate once
if (null === self::$_rand) {
self::$_rand = rand();
}
$rand = self::$_rand;
var_dump(__METHOD__, getmypid(), 'provided rand', $rand);
return ['rand' => [$rand]];
}
#dirk-scholten is right. You SHOULD be creating a new object for each test. It's a GOOD testing practice. Frankly it looks more like you are testing the data and not testing the code, which is fine I guess, it's just not the typical use of PHPUnit. Based on the assumption that you want to make sure every user in the database has a thumbnail image (just guessing), I would go with the following:
<?php
class DashboardDataTest extends PHPUnit\Framework\TestCase {
private $dashboard;
public function setUp() {
$this->dashboard = new Dashboard();
}
/**
* Test Org Thumb Image Existence
* param org profile image : array
*
* #dataProvider getOrgProfileImages
*
* #param int $user_id
*/
public function testThumbnailImageExists(int $user_id){
$thumbnail = $this->dashboard->get_member_thumbnail($user_id);
$this->assertNotNull($thumbnail);
}
public function geOrgUserIDs() : array {
$dashboard = new Dashboard();
// Something that is slow
$user_ids = $dashboard->get_all_the_member_user_ids();
$data = [];
foreach($user_ids as $user_id){
$data[] = [$user_id];
}
return $data;
}
}
Each data provider will get called once and only once before the tests. You do not need a static data fixture on the class because phpunit handles the data fixture for you when you use data providers.

How to PHPUnit test a method with no return value?

I am trying to test methods from the following class I have written (there are more functions than what is shown, basically, one function for each is_*() method):
class Validate {
private static $initialized = false;
/**
* Construct won't be called inside this class and is uncallable from the outside. This prevents
* instantiating this class. This is by purpose, because we want a static class.
*/
private function __construct() {}
/**
* If needed, allows the class to initialize itself
*/
private static function initialize()
{
if(self::$initialized) {
return;
} else {
self::$initialized = true;
//Set any other class static variables here
}
}
...
public static function isString($string) {
self::initialize();
if(!is_string($string)) throw new InvalidArgumentException('Expected a string but found ' . gettype($string));
}
...
}
When I test if the methods throw an exception on invalid input, it works great! However, when I test if the method works as expected, PHPUnit complains because I have no assert in the test. The specific error is:
# RISKY This test did not perform any assertions
However, I don't have any value to assert against so I'm not sure how to overcome this.
I've read some about testing static methods, but that mostly seems to cover dependencies between static methods. Further, even non-static methods could have no return value, so, how to fix this?
For reference, my test code:
class ValidateTest extends PHPUnit_Framework_TestCase {
/**
* #covers ../data/objects/Validate::isString
* #expectedException InvalidArgumentException
*/
public function testIsStringThrowsExceptionArgumentInvalid() {
Validate::isString(NULL);
}
/**
* #covers ../data/objects/Validate::isString
*/
public function testIsStringNoExceptionArgumentValid() {
Validate::isString("I am a string.");
}
}
Test void function with assertNull:
/**
* #covers ../data/objects/Validate::isString
*/
public function testIsStringNoExceptionArgumentValid() {
$this->assertNull( Validate::isString("I am a string.") );
}
To prevent the warning about the assertions you can use the #doesNotPerformAssertions annotation as explained in the documentation: https://phpunit.de/manual/current/en/appendixes.annotations.html#idp1585440
Or if you prefer code over annotation:
$this->doesNotPerformAssertions();
One solution I have come upon is the following, based on example 2.12 from chapter 2 of PHPUnit. It feels a little hacky to me, but it's the best I've found so far. Also, based on this PHPUnit Gitub issue discussion, it seems several other people want this feature but that there are no plans to implement it.
Change testIsStringNoExceptionArgumentValid() to the following:
/**
* #covers ../data/objects/Validate::isString
*/
public function testIsStringNoExceptionArgumentValid() {
try {
Validate::isString("I am a string.");
} catch (InvalidArgumentException $notExpected) {
$this->fail();
}
$this->assertTrue(TRUE);
}
If you want to test a void function you only need to run it without any assertion.
If it there is any issue it will throw an exception and test will fails. No need to put $this->assertTrue(TRUE); as you are not running an assertion and having assertions is not required to test your code.
You will get a message like
Time: 7.39 seconds, Memory: 16.00 MB
OK (1 test, 0 assertions)
Process finished with exit code 0

phpunit mock method multiple calls with different arguments

Is there any way to define different mock-expects for different input arguments? For example, I have database layer class called DB. This class has method called "Query ( string $query )", that method takes an SQL query string on input. Can I create mock for this class (DB) and set different return values for different Query method calls that depends on input query string?
It's not ideal to use at() if you can avoid it because as their docs claim
The $index parameter for the at() matcher refers to the index, starting at zero, in all method invocations for a given mock object. Exercise caution when using this matcher as it can lead to brittle tests which are too closely tied to specific implementation details.
Since 4.1 you can use withConsecutive eg.
$mock->expects($this->exactly(2))
->method('set')
->withConsecutive(
[$this->equalTo('foo'), $this->greaterThan(0)],
[$this->equalTo('bar'), $this->greaterThan(0)]
);
If you want to make it return on consecutive calls:
$mock->method('set')
->withConsecutive([$argA1, $argA2], [$argB1], [$argC1, $argC2])
->willReturnOnConsecutiveCalls($retValueA, $retValueB, $retValueC);
The PHPUnit Mocking library (by default) determines whether an expectation matches based solely on the matcher passed to expects parameter and the constraint passed to method. Because of this, two expect calls that only differ in the arguments passed to with will fail because both will match but only one will verify as having the expected behavior. See the reproduction case after the actual working example.
For you problem you need to use ->at() or ->will($this->returnCallback( as outlined in another question on the subject.
Example:
<?php
class DB {
public function Query($sSql) {
return "";
}
}
class fooTest extends PHPUnit_Framework_TestCase {
public function testMock() {
$mock = $this->getMock('DB', array('Query'));
$mock
->expects($this->exactly(2))
->method('Query')
->with($this->logicalOr(
$this->equalTo('select * from roles'),
$this->equalTo('select * from users')
))
->will($this->returnCallback(array($this, 'myCallback')));
var_dump($mock->Query("select * from users"));
var_dump($mock->Query("select * from roles"));
}
public function myCallback($foo) {
return "Called back: $foo";
}
}
Reproduces:
phpunit foo.php
PHPUnit 3.5.13 by Sebastian Bergmann.
string(32) "Called back: select * from users"
string(32) "Called back: select * from roles"
.
Time: 0 seconds, Memory: 4.25Mb
OK (1 test, 1 assertion)
Reproduce why two ->with() calls don't work:
<?php
class DB {
public function Query($sSql) {
return "";
}
}
class fooTest extends PHPUnit_Framework_TestCase {
public function testMock() {
$mock = $this->getMock('DB', array('Query'));
$mock
->expects($this->once())
->method('Query')
->with($this->equalTo('select * from users'))
->will($this->returnValue(array('fred', 'wilma', 'barney')));
$mock
->expects($this->once())
->method('Query')
->with($this->equalTo('select * from roles'))
->will($this->returnValue(array('admin', 'user')));
var_dump($mock->Query("select * from users"));
var_dump($mock->Query("select * from roles"));
}
}
Results in
phpunit foo.php
PHPUnit 3.5.13 by Sebastian Bergmann.
F
Time: 0 seconds, Memory: 4.25Mb
There was 1 failure:
1) fooTest::testMock
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-select * from roles
+select * from users
/home/.../foo.php:27
FAILURES!
Tests: 1, Assertions: 0, Failures: 1
From what I've found, the best way to solve this problem is by using PHPUnit's value-map functionality.
Example from PHPUnit's documentation:
class SomeClass {
public function doSomething() {}
}
class StubTest extends \PHPUnit_Framework_TestCase {
public function testReturnValueMapStub() {
$mock = $this->getMock('SomeClass');
// Create a map of arguments to return values.
$map = array(
array('a', 'b', 'd'),
array('e', 'f', 'h')
);
// Configure the mock.
$mock->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));
// $mock->doSomething() returns different values depending on
// the provided arguments.
$this->assertEquals('d', $stub->doSomething('a', 'b'));
$this->assertEquals('h', $stub->doSomething('e', 'f'));
}
}
This test passes. As you can see:
when the function is called with parameters "a" and "b", "d" is returned
when the function is called with parameters "e" and "f", "h" is returned
From what I can tell, this feature was introduced in PHPUnit 3.6, so it's "old" enough that it can be safely used on pretty much any development or staging environments and with any continuous integration tool.
It seems Mockery (https://github.com/padraic/mockery) supports this. In my case I want to check that 2 indices are created on a database:
Mockery, works:
use Mockery as m;
//...
$coll = m::mock(MongoCollection::class);
$db = m::mock(MongoDB::class);
$db->shouldReceive('selectCollection')->withAnyArgs()->times(1)->andReturn($coll);
$coll->shouldReceive('createIndex')->times(1)->with(['foo' => true]);
$coll->shouldReceive('createIndex')->times(1)->with(['bar' => true], ['unique' => true]);
new MyCollection($db);
PHPUnit, this fails:
$coll = $this->getMockBuilder(MongoCollection::class)->disableOriginalConstructor()->getMock();
$db = $this->getMockBuilder(MongoDB::class)->disableOriginalConstructor()->getMock();
$db->expects($this->once())->method('selectCollection')->with($this->anything())->willReturn($coll);
$coll->expects($this->atLeastOnce())->method('createIndex')->with(['foo' => true]);
$coll->expects($this->atLeastOnce())->method('createIndex')->with(['bar' => true], ['unique' => true]);
new MyCollection($db);
Mockery also has a nicer syntax IMHO. It appears to be a tad slower than PHPUnits built-in mocking capability, but YMMV.
Intro
Okay I see there is one solution provided for Mockery, so as I don't like Mockery, I am going to give you a Prophecy alternative but I would suggest you first to read about the difference between Mockery and Prophecy first.
Long story short: "Prophecy uses approach called message binding - it means that behaviour of the method does not change over time, but rather is changed by the other method."
Real world problematic code to cover
class Processor
{
/**
* #var MutatorResolver
*/
private $mutatorResolver;
/**
* #var ChunksStorage
*/
private $chunksStorage;
/**
* #param MutatorResolver $mutatorResolver
* #param ChunksStorage $chunksStorage
*/
public function __construct(MutatorResolver $mutatorResolver, ChunksStorage $chunksStorage)
{
$this->mutatorResolver = $mutatorResolver;
$this->chunksStorage = $chunksStorage;
}
/**
* #param Chunk $chunk
*
* #return bool
*/
public function process(Chunk $chunk): bool
{
$mutator = $this->mutatorResolver->resolve($chunk);
try {
$chunk->processingInProgress();
$this->chunksStorage->updateChunk($chunk);
$mutator->mutate($chunk);
$chunk->processingAccepted();
$this->chunksStorage->updateChunk($chunk);
}
catch (UnableToMutateChunkException $exception) {
$chunk->processingRejected();
$this->chunksStorage->updateChunk($chunk);
// Log the exception, maybe together with Chunk insert them into PostProcessing Queue
}
return false;
}
}
PhpUnit Prophecy solution
class ProcessorTest extends ChunkTestCase
{
/**
* #var Processor
*/
private $processor;
/**
* #var MutatorResolver|ObjectProphecy
*/
private $mutatorResolverProphecy;
/**
* #var ChunksStorage|ObjectProphecy
*/
private $chunkStorage;
public function setUp()
{
$this->mutatorResolverProphecy = $this->prophesize(MutatorResolver::class);
$this->chunkStorage = $this->prophesize(ChunksStorage::class);
$this->processor = new Processor(
$this->mutatorResolverProphecy->reveal(),
$this->chunkStorage->reveal()
);
}
public function testProcessShouldPersistChunkInCorrectStatusBeforeAndAfterTheMutateOperation()
{
$self = $this;
// Chunk is always passed with ACK_BY_QUEUE status to process()
$chunk = $this->createChunk();
$chunk->ackByQueue();
$campaignMutatorMock = $self->prophesize(CampaignMutator::class);
$campaignMutatorMock
->mutate($chunk)
->shouldBeCalled();
$this->mutatorResolverProphecy
->resolve($chunk)
->shouldBeCalled()
->willReturn($campaignMutatorMock->reveal());
$this->chunkStorage
->updateChunk($chunk)
->shouldBeCalled()
->will(
function($args) use ($self) {
$chunk = $args[0];
$self->assertTrue($chunk->status() === Chunk::STATUS_PROCESSING_IN_PROGRESS);
$self->chunkStorage
->updateChunk($chunk)
->shouldBeCalled()
->will(
function($args) use ($self) {
$chunk = $args[0];
$self->assertTrue($chunk->status() === Chunk::STATUS_PROCESSING_UPLOAD_ACCEPTED);
return true;
}
);
return true;
}
);
$this->processor->process($chunk);
}
}
Summary
Once again, Prophecy is more awesome! My trick is to leverage the messaging binding nature of Prophecy and even though it sadly looks like a typical, callback javascript hell code, starting with $self = $this; as you very rarely have to write unit tests like this I think it's a nice solution and it's definitely easy to follow, debug, as it actually describes the program execution.
BTW: There is a second alternative but requires changing the code we are testing. We could wrap the troublemakers and move them to a separate class:
$chunk->processingInProgress();
$this->chunksStorage->updateChunk($chunk);
could be wrapped as:
$processorChunkStorage->persistChunkToInProgress($chunk);
and that's it but as I didn't want to create another class for it, I prefer the first one.

Categories