Phpunit using zend framework 3 and doctrine, Mocking not working

I’m using zend-test in zf3, using doctrine, when I run the test for PostController showAction(), it is showing following error

$ vendor/bin/phpunit --testsuite Post --stderr
PHPUnit 7.5.2 by Sebastian Bergmann and contributors.

F      1 / 1 (100%)

Time: 169 ms, Memory: 16.00MB

There was 1 failure:

1) PostTest\Controller\PostControllerTest::testIfPostDetailsShownSuccessfully
Failed asserting response code "200", actual status code is "500"

Exceptions raised:
Exception 'TypeError' with message 'Return value of Post\Entity\Post::getUser() must be an instance of User\Entity\User, null returned' in /var/www/html/crud/module/Post/src/Entity/Post.php:122

/var/www/html/crud/vendor/zendframework/zend-test/src/PHPUnit/Controller/AbstractControllerTestCase.php:451
/var/www/html/crud/module/Post/test/Controller/PostControllerTest.php:95

PostController showAction()

public function showAction()
{
    $postId = $this->params()->fromRoute('postId');
    $post = $this->postService->getPost($postId);

    return new ViewModel([
        'post' => $post
    ]);
} 

Post Service getPost()

public function getPost($postId = null)
{
    $post = $this->entityManager->getRepository(Post::class)->find($postId);

    return $post;
}

PostControllerTest testIfPostDetailsShownSuccessfully()

public function testIfPostDetailsShownSuccessfully()
{

            $mockedEm = $this->createMock(EntityManager::class);

            $postRepositoryMock = $this->createMock(PostRepository::class);
            $postRepositoryMock->expects($this->any())
                ->method('find')
                ->willReturn($this->getPostMock());

            $postRepositoryMock->expects($this->any())
                ->method('findOneBy')
                ->willReturn($this->getPostMock());

            $userRepositoryMock = $this->createMock(UserRepository::class);
            $userRepositoryMock->expects($this->any())
                ->method('find')
                ->willReturn(new User());

            $userRepositoryMock->expects($this->any())
                ->method('findOneBy')
                ->willReturn(new User());

            $userEntityMock = $this->createMock(UserRepository::class);
            $userEntityMock->expects($this->any())
                ->method('find')
                ->willReturn(new User());

            $this->dispatch('/post/1');
            $this->assertResponseStatusCode(200);
  }

/**
 * @return MockObject
 */
public function getPostMock()
{
    $user = new User();
    $user->setEmail('a@a.in');

    $postMock = $this->createMock(Post::class);
    $postMock->expects($this->any())
        ->method('getUser')
        ->willReturn($user);

    return $postMock;
}

A post always has one user, I have getUser() method in Post entity which returns User entity object. But I’m unable to mock post object and it always recieving getUser as null.

Any help is much appreciated.

Without being much of help here (and not trying to be too offensive), let me try to explain how I handle these situations.

Writing tests that involve doctrine in the way you do it, assuming you get them working, would only prove that your test-writing skills are efficient.
In cases like this, you only write tests for the sake of code coverage, but you don’t test anything. All you prove is that your mocking is working.

I would completely ignore/skip these type of tests and create integration tests, with a DB like SQLite and do some real CRUD work. Then you would get a) coverage and b) you actually see if your DBAL integration is working as expected.

2 Likes

@guidofaecke This is not my complete tests, I started writing test cases and faces problem while mocking doctrine classes, once I resolve this, I would definitly move ahead and write more test cases and cover more code coverage. Here I am only expecting to resolve mocking issue. I write all the code in my question necessary to understand the problem, if you need anything more of code, let me know I will add it in the question.

What’s the trace for that’s exception? I don’t see explicit calls to that getter.

Also, since both Post and User are not interchangeable concepts in your system, I wouldn’t mock those two

@ocramius If you notice getPost() method of PostService, It calls find() method of Post entity(doctrine method) where it fetches details of Post based on Postid. Now, Post entity has relationship with User, so Post entity has getUser() (getter) method as well. When it fetches the row of Post table and if the user column of that row is null, then it show that error which I posted in question. And if I insert any user id in user column of that row then the test cases executed successfully. Now my question is it is not accepting the data of the mock but its fetching records from the database itself. Because mocking is not working here.