I have a class ApplicationForm that extends ContentEntity. In my other class ApplicationFormForm (Poorly named, I know) I extend ContentEntityForm which in turn inherits from EntityForm. In one of those parent classes, a property called $entity is created, which is available in my class ApplicationFormForm.
The $entity property has all the methods I created on it and I use it in my submitForm method:
public function submitForm($form, FormStateInterface $form_state) {
// Code omitted for brevity
$stepsCompleted = $this->entity->getStepsCompleted();
}
Now, the problem arises when I try and unit test my submitForm method, because entity is null and therefore getStepsCompleted does not exist.
To get around this, I created an interface of my ApplicationForm class and turned ApplicationForm into a service, and injected it into my ApplicationFormForm class (type hinting the parameter as the newly created interface so I can mock it later).
The problem is, as mentioned previously, ApplicationForm inherits from other classes, and these classes have other parameters in their constructors which are not services. Specifically:
public function __construct(array $values, $entity_type) {
}
So when I try and inject my new service, it complains that I am missing argument 1 and 2 of the constructor. So... I'm pretty stuck. Does anyone have a solution so I can unit test my method?
Update - Here is my unit test. It's extending FormTestBase.
/**
* Set up method which is called before any tests are
* run. Mocks of the services that the class being tested rely on are
* created. These mocks are then passed to the container, so they are
* available to the methods under test.
*
* @return void
*/
public function setUp() {
parent::setUp();
$container = new ContainerBuilder();
$mockEntityTypeManager = $this
->getMockBuilder('\Drupal\Core\Entity\EntityTypeManager')
->disableOriginalConstructor()
->getMock();
$container->set('entity_type.manager', $mockEntityTypeManager);
$applicationForm = new ApplicationFormForm(
$mockEntityTypeManager,
);
$this->applicationForm = $applicationForm;
\Drupal::setContainer($container);
}
/**
* @dataProvider submitFormDataProvider
* @param $form array
* @covers ::submitForm
*/
public function testSubmitForm($form) {
$form_state = new FormState();
$form_state = $this->applicationForm->submitForm($form, $form_state);
// Assertion will go here.
}
/**
* @return array
*/
public function submitFormDataProvider() {
$form['base'] = array(
'#type' => 'fieldset',
'#tree' => true,
);
$form['base']['value'] = array(
'#type' => 'textfield',
'#title' => '<span class="form-required">Foo</span>',
'#value' => '',
'#attributes' => array(
'data-required' => 'required'
),
'#parents' => array(
'base'
)
);
return array(
array($form)
);
}
As mentioned before, I can't see a way to mock the entity property like I have with EntityTypeManager as $entity is inherited from the parent class and has dependencies in the constructor.
::setEntity
, which you could use to set that property. In the normal form flow,EntityFormBuilder
calls that method so that it can useFormBuilder
to build the form array via::buildForm
. I think that you might run into issues with submitForm because its parent will call$this->entity->save()
at some point as well so I don't want to just add use setEntity as an answer.