Skip to content

Simplify tests with a single mockFileSave helper #80

Description

@DenTray

Description
What needs to be done?
Add a mockFileSave() helper to PHPFileBuilderTestMockTrait. It does two steps at once: it builds the path to a file inside tests/Support/OriginStructures/, and it mocks file_put_contents with the expected new content of that file. It returns the path, because the builder constructor needs it.
mockFileSave() takes the origin structure file name and an optional result fixture name. When the result fixture name is not passed, use the origin structure name. Six tests already use the same name for both: trait.php, class_with_properties.php, empty_php_file.php, bootstrap_empty.php, bootstrap_configured.php, bootstrap_with_render.php.
Add an expectNoFileSave() helper to the same trait. It expects file_put_contents to never be called.
Replace the repeated arrange block in all 32 places in PHPFileBuilderTest and AppBootstrapBuilderTest with a mockFileSave() call. Where the result fixture name equals the origin structure name, pass one argument only.
Call expectNoFileSave() in the 20 tests that assert an exception and still call save(). Today these tests do not mock file_put_contents at all, so if the builder stops throwing, the test writes the file for real and overwrites the source file in tests/Support/OriginStructures/.
Remove callFilePutContent() from the trait. Its $flags argument is never passed by any test, and PHPFileBuilder::save() calls file_put_contents() with two arguments.

Expected Outcome
What is the expected result?
A test that saves a file has one mockFileSave() line instead of six lines of arrange code.
The string RonasIT\Larabuilder\Builders is written once, inside PHPFileBuilderTestMockTrait.
callFilePutContent() is gone and has no callers left.
The 20 exception tests fail when the builder stops throwing, because expectNoFileSave() forbids the write.
The full test suite passes, and the number of tests and assertions is the same as before the change.

Verification Scenarios
How can this be tested?
Run the full test suite. Every test passes, and the test and assertion counts match the counts taken before the change.
Change a builder so it writes wrong content, then run the suite. The test that mocks that file with mockFileSave() fails and shows the difference between the expected fixture and the real content.
Remove the structure type check from one visitor so it stops throwing, then run the suite. The matching exception test fails, because expectNoFileSave() catches the real call to file_put_contents.

Resources
Helpers
protected function mockFileSave(string $originStructure, ?string $resultFixture = null): string
{
$file = $this->generateOriginalStructurePath($originStructure);

$this->mockNativeFunction(
    'RonasIT\Larabuilder\Builders',
    $this->functionCall('file_put_contents', [$file, $this->getFixture($resultFixture ?? $originStructure)]),
);

return $file;

}

protected function expectNoFileSave(): void
{
$this->getFunctionMock('RonasIT\Larabuilder\Builders', 'file_put_contents')
->expects($this->never());
}
Test before and after
// before
public function testAddArrayPropertyItem(): void
{
$file = $this->generateOriginalStructurePath('class_with_properties.php');

$this->mockNativeFunction(
    'RonasIT\Larabuilder\Builders',
    $this->callFilePutContent($file, 'class_with_array_properties.php'),
);

new PHPFileBuilder($file)
    ->addArrayPropertyItem('fillable', 'age')
    ->save();

}

// after
public function testAddArrayPropertyItem(): void
{
$file = $this->mockFileSave('class_with_properties.php', 'class_with_array_properties.php');

new PHPFileBuilder($file)
    ->addArrayPropertyItem('fillable', 'age')
    ->save();

}
Exception test before and after
// before
public function testSetPropertyNotClassTrait(): void
{
$file = $this->generateOriginalStructurePath('enum.php');

$this->assertExceptionThrew(InvalidStructureTypeException::class, "'SetProperty' operation may only be applied to: Class, Trait.");

new PHPFileBuilder($file)->setProperty('newString', 'some string')->save();

}

// after
public function testSetPropertyNotClassTrait(): void
{
$file = $this->generateOriginalStructurePath('enum.php');

$this->expectNoFileSave();
$this->assertExceptionThrew(InvalidStructureTypeException::class, "'SetProperty' operation may only be applied to: Class, Trait.");

new PHPFileBuilder($file)->setProperty('newString', 'some string')->save();

}
Tests that need expectNoFileSave()
PHPFileBuilderTest: testSetPropertyNotClassTrait, testAddArrayPropertyItemThrowsException, testAddArrayPropertyItemNotClassTrait, testRemoveArrayPropertyItemThrowsException, testRemoveArrayPropertyUnexpectedPropertyExceptionNull, testRemoveArrayPropertyNotClassTrait, testAddTraitsNotClassTraitEnum, testInsertCodeToMethodNotExists, testInsertCodeToMethodInvalidCode, testInsertCodeToMethodNotClassTraitEnum, testInsertCodeToMethodWhenMethodNotExist, testAddMethodAlreadyExists, testAddMethodNotClassTraitEnum, testAddReturnedArrayItemThrowsOnNonArrayReturn, testAddReturnedArrayItemThrowsOnMultipleReturnStatements, testAddReturnedArrayItemThrowsOnMethodNotFound, testAddReturnedArrayItemNotClassTraitEnum, testAddReturnedArrayItemInvalidCode.
AppBootstrapBuilderTest: testAddExceptionsRenderInvalidBody, testInvalidBootstrapAppFileException.
testInvalidPhpFileThrowsException stays as it is, because it never calls save().

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions