R
R
romajke2018-12-27 10:50:50
Unit testing
romajke, 2018-12-27 10:50:50

Why is this strange behavior happening when testing Codeception?

The application is written in Yii2. There is a model inherited from the yii\base\Model class , which contains several AR models. Below is the model code.

class InquiryForm extends \yii\base\Model
{
    /**
     * @var ActiveRecord Адрес регистрации клиента
     */
    public $regAddress;

    /**
     * @var ActiveRecord Анкета
     */
    public $inquiry;

    /**
     * @inheritdoc
     */
    public function load($data, $formName = null)
    {
        $load = [
            'inquiry' => $this->inquiry,
            'regAddress' => $this->regAddress,
        ];
        $success = false;

        foreach ($load as $name => $form) {
            $success = $form->load($data, $formName !== '' ? null : $name);
        }
        return $success;
    }
}

I'm trying to test the model 's load method with codeception .
Here is the test code:
To begin with, in the before() method, I disconnect the AR model from interacting with the base, "wetting" the "save" & "attributes" methods as follows:
protected function _before()
    {
        $this->_address = $this->createFormMock(Address::class,
            [
                'field1',
                'field2',
                'field3',
                'field4',
                'field5',
                'field6'
            ]
        );

        $this->_inquiry = $this->createFormMock(InquiryLogical::class,
            [
                'field1',
                'field2',
                'field3',
                'field4',
                'field5',
                'field6'
            ]
        );
    }

    protected function createFormMock(string $class, array $attributes)
    {
        $mockObject = $this->getMockBuilder($class)
            ->setMethods(['save', 'attributes'])
            ->getMock();
        $mockObject->method('save')->willReturn(true);
        $mockObject->method('attributes')->willReturn($attributes);

        return $mockObject;
    }

And finally, I try to test the method:
public function testLoadForm()
    {
        $data = [
            'there is some data from $_POST'
        ];

        $form = new InquiryForm(['inquiry' => $this->_inquiry, 'regAddress' => $this->_address]);

        $this->assertTrue($form->load($data));
    }

At first, for a very long time, I could not understand why my simplest test did not work out in any way and all the time gave the error Failed asserting that false is true. At first I thought that somehow the mockObject was created incorrectly or the data in the $data array was incorrect , but no,
everything was correct there (when loading the same data on the page, everything works correctly).
Some time later, the following interesting dependency was discovered:
If the order of loaded methods in the method under test is as follows:
$load = [
            'inquiry' => $this->inquiry,
            'regAddress' => $this->regAddress,
        ];

and in the test I create the form object like this:
$form = new InquiryForm(['inquiry' => $this->_inquiry, 'regAddress' => new Address()]);

then the test works.
And vice versa, if you change the order in the method:
$load = [
            'regAddress' => $this->regAddress,
            'inquiry' => $this->inquiry,
        ];

and in the test create a form object like this
$form = new InquiryForm(['inquiry' => new Inquiry(), 'regAddress' => $this->_address]);

then the test will work just as well.
This confirms that the mocks and test data are created correctly. But I can't figure out why this is happening? I will be glad for any help.

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question