Expect a stub doesn't work
Opened this issue · 2 comments
I use a stub to make get_post
available, which returns a mock of WP_Post
:
$post = Mockery::mock(\WP_Post::class);
$post->ID = 1;
$post->post_content = '<!-- wp:heading {"level":1} -->
<h1 class="wp-block-heading">Heading 1</h1>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>This is content.</p>
<!-- /wp:paragraph -->';
$post->post_status = 'publish';
$post->post_type = 'page';
stubs(
[
'get_post' => $post,
'get_queried_object_id' => 1,
]
);
This is my test:
expect('get_post')->once();
$this->assertEquals(true, My_Class::get_instance()->has_content('This is content.'));
$this->assertEquals(true, My_Class::get_instance()->has_content('This is content.'));
My_Class
:
<?php
final class My_Class {
/**
* @var array A list of available content
*/
private array $has_content = [];
public function has_content( string $content ): bool {
// already searched for this content, return stored value
if ( isset( $this->has_content[ $content ] ) ) {
return $this->has_content[ $content ];
}
$post = \get_post( \get_queried_object_id() );
if ( ! $post instanceof WP_Post ) {
$this->has_content[ $content ] = false;
return false;
}
// search in post content
if ( \strpos( $post->post_content, $content ) !== false ) {
$this->has_content[ $content ] = true;
return true;
}
return false;
}
}
Since I want to test whether I already searched for the content, which would result in an early return for the second run, I thought expect('get_post')->once();
would be correct. However, the error message implies it is not:
[Mockery\Exception\InvalidCountException] Method get_post(<Any Arguments>) from Mockery_1 should be called
exactly 1 times but called 0 times.
Am I doing wrong here?
As a workaround, I currently test for expect('strpos')->once();
, which works when allowing redefining internals for strpos
in the patchwork.json
.
I think this is failing because you are both doing a stub and an expectation from the same function.
On the same test, you can't do both things to the same function. This should be documented IIRC.
I would suggest to use the expectations only, like this:
class MyTest extends TestCase
{
public function testHasContentCallGetPostOnce(): void
{
$id = random_int(1, 100);
$content = <<<'TXT'
<!-- wp:heading {"level":1} -->
<h1 class="wp-block-heading">Heading 1</h1>
<!-- /wp:heading -->
<!-- wp:paragraph -->
<p>This is content.</p>
<!-- /wp:paragraph -->
TXT;
$post = $this->stubPost($id, ['content' => $content]);
\Brain\Monkey\Functions\expect('get_queried_object_id')
->once()
->andReturn($id);
\Brain\Monkey\Functions\expect('get_post')
->once()
->with($id)
->andReturn($post);
$class = My_Class::get_instance();
static::assertTrue($class->has_content($content));
static::assertTrue($class->has_content($content));
}
private function stubPost(int $id = 1, array $properties = []): \WP_Post
{
$post = \Mockery::mock(\WP_Post::class);
$post->ID = $id;
foreach ($properties as $key => $value) {
$property = "post_{$key}";
$post->{$property} = $value;
}
$post->post_content ??= '';
$post->post_type ??= 'page';
$post->post_status ??= 'publish';
return $post;
}
}
Thank you, that worked just fine!
I’ll leave it open since adding it to the documentation would be indeed nice. 🙂