Unit testing db example?

Hi all,

Just got started with Yii 2 after having done a lot of development with Yii 1. For the most part things are going smoothly, except for one thing: I can’t get unit testing with databases to work.

Let’s say I have a class app/models/User (which extends ActiveRecord) and I want to create a new instance of that class and save it in one of my tests. How would I go about that?

I’ve set up my environment as per tests/README.md and my test class (tests/codeception/unit/models/UserTest.php) looks as follows:




namespace tests\codeception\unit\models;                                                     

                                                                                             

use app\tests\fixtures\UserFixture;                                                          

use yii\codeception\TestCase;                                                                

                                                                                             

class UserTest extends TestCase                                                              

{                                                                                            

                                                                                             

    public function testSomething()

    {

        $user = new User();

        // Do something.        

    }


                                                          

}                



This works fine.

However, what I would really like to do is do some work with the database in _before() and _after(), and that doesn’t work:




<?php                                                                                        

                                                                                             

namespace tests\codeception\unit\models;                                                     

                                                                                             

use yii\codeception\DbTestCase;                                                              

use app\models\User;                                                                         

                                                                                             

class UserTest extends DbTestCase                                                            

{                                                                                            

    protected $user;                                                                         

                                                                                             

    protected function _before()                                                             

    {                                                                                        

        $this->user = new User();                                                            

        $this->user->email = uniqid('test.device', true)                                     

            . '@unittest.icalab.nl';                                                         

        $this->user->setPassword('irrelevant');                                              

        $this->user->save();                                                                 

    }                                                                                        

                                                                                             

    protected function _after()                                                              

    {                                                                                        

        if($this->user)                                                                      

        {                                                                                    

            $this->user->delete();                                                           

        }                                                                                    

    }                                                                                        

    public function testSomething()                                                          

    {                                                                                        

        $user = User::findOne(                                                               

            ['email' => $this->user->email]);                                                

        $this->assertNotNull($user,                                                          

            'Users can be retrieved from the database.');                                    

    }                                                                                        

                                   

}



(never mind why - it’s just an example)

When I try to run this I get:




Trying to test something (tests\codeception\unit\models\UserTest::testSomething)                                                 PHP Fatal error:  Call to a member function getDb() on a non-object in /home/developer/projects/ggdgz_backend/basic/vendor/yiisoft/yii2/db/ActiveRecord.php on line 124

PHP Fatal error:  Call to a member function has() on a non-object in /home/developer/projects/ggdgz_backend/basic/vendor/yiisoft/yii2/web/ErrorHandler.php on line 70



This is caused by the call to new User in the _before method.

So apparently Yii::$app is not yet available in _before.

My question now is twofold:

  1. Specifically: at what point can I run database code that will be executed before and after every test?

  2. Is there a document somewhere that provides a complete example of a database test in Yii 2 using codeception?

All the documentation I’ve found is either unfinished (the Yii 2 guide section on unit testing) or provides incomplete examples where only the very basics are done (such as in my first example above).

If someone has a suggestion, I’d be much obliged.

Are you searching for anything Yii2 specific in common with Codeseption or do you want the PHPUnit pattern for DB testing?: https://phpunit.de/manual/current/en/database.html

Sorry, I managed to hit the save button before finishing my post. It’s now done.

But what I’m really looking for is an example of a non-trivial ActiveRecord unit test using Codeception. All the available documentation (that I have found, anyway) goes through the basics only.

have you got the test database setup correctly?

Consider that for unit tests you can only use PHPUnit styled tests, and CodeCeption Unit tests are not working in Yii (and possibly to be removed in the future)

Last time I tried I think that _after() and _before() (which are syntactic sugar made by CodeCeption) should have been available, if things have changed in the meantime (see above), you might be well revert back to the classic PHPUnit original functions setUp() and tearDown().

Also, you might need to have a look at fixtures if you want to implement tests with full control.

Why do you think that Codeception Unit tests are not working in Yii ? Mine are working just great…

I’m mostly talking about some of the additional functionality that CodeCeption is adding, such as the Mock static class for creating stubs and mocks.

I’ve got the general impression that PHPUnit has become some sort of standard and using CodeCeption syntactic sugar might not benefit many.