При Юнит Тестах есть ошибка Call to a member function getDb() on null

Всё про тестирование в Yii 2.0
Ответить
sergey-o90
Сообщения: 11
Зарегистрирован: 2021.05.28, 21:06

При Юнит Тестах есть ошибка Call to a member function getDb() on null

Сообщение sergey-o90 »

Сразу скажу, ошибка я знаю о чём, но проблема глубже, т.к. она проявляется исключительно на Юнит Тестировании

Если делать перебор данных из модели в методе тестирования, то всё работает.

Рабочий вариант:

Код: Выделить всё

    <?php
    
    namespace tests\unit\services\user;
    
    use app\models\User;
    use app\services\User as UserService;
    
    use Codeception\Test\Unit;
    
    class UserTest extends Unit {
    	
    	/**
    	 * @var \UnitTester
    	 */
    	protected $tester;	
    	protected function _before() { }	
    	protected function _after() { }
    	
    	public function testUserIsActive() {	
    		$users = [
    			User::findOne(['id' => 1]),
    			User::findOne(['id' => 2]),
    		];
    		
    		foreach ($users as $user) {
    			$userService = new UserService($user);
    			self::assertEquals($userService->isActive(), true);
    		}
    	}
    }

Если же данные выносить в метод и прикреплять аннотацию @dataProvider, то вылетает ошибка указанная в шапке вопроса

Нерабочий вариант:

Код: Выделить всё

    <?php
    
    namespace tests\unit\services\user;
    
    use app\models\User;
    use app\services\User as UserService;
    
    use Codeception\Test\Unit;
    
    class UserTest extends Unit {
    	
    	/**
    	 * @var \UnitTester
    	 */
    	protected $tester;	
    	protected function _before() { }	
    	protected function _after() { }
    	
    	/**
    	* @dataProvider getUsers
    	*/
    	public function testUserIsActive($user, $result) {	
    		$userService = new UserService($user);
    		self::assertEquals($userService->isActive(), $result);
    	}
    	
    	public function getUsers() {
    		return [
    			[User::findOne(['id' => 1]) => true],
    			[User::findOne(['id' => 2]) => true],
    		];
    	}
    }
В инете писали (даже на этом форуме: viewtopic.php?p=248830#p248830), что проблема в старой версии codeception и надо поставить 2.4 и выше (например тут: https://godmodeuser.com/p/11 этим лечат несколько степеней `member function`). Поставил 2.5.6, ошибка осталась

Код: Выделить всё

    "codeception/codeception": "2.5.6",
    "codeception/verify": "1.0.0",
    "codeception/specify": "1.0"

Может быть надо настройки какие-то дополнительные прописывать где-либо?



В папке test/_bootstrap.php

Код: Выделить всё

    <?php
    ini_set('xdebug.max_nesting_level', 1000);

    define('YII_ENV', 'test');
    defined('YII_DEBUG') or define('YII_DEBUG', true);
    
    require_once __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
    require __DIR__ .'/../vendor/autoload.php';
    
    $config = require(__DIR__ . '/../config/test.php');
    Yii::setAlias('@app', __DIR__ . '/../');

index-test.php

Код: Выделить всё

    <?php
    
    // NOTE: Make sure this file is not accessible when deployed to production
    if (!in_array(@$_SERVER['REMOTE_ADDR'], ['127.0.0.1', '::1'])) {
    	die('You are not allowed to access this file.');
    }
    
    defined('YII_DEBUG') or define('YII_DEBUG', true);
    defined('YII_ENV') or define('YII_ENV', 'test');
    
    require __DIR__ . '/../vendor/autoload.php';
    require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
    
    $config = require __DIR__ . '/../config/test.php';
    
    (new yii\web\Application($config))->run();
sergey-o90
Сообщения: 11
Зарегистрирован: 2021.05.28, 21:06

Re: При Юнит Тестах есть ошибка Call to a member function getDb() on null

Сообщение sergey-o90 »

Никто не знает ответа? Я ведь тоже до сих пор не знаю
Аватара пользователя
ElisDN
Сообщения: 5841
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: При Юнит Тестах есть ошибка Call to a member function getDb() on null

Сообщение ElisDN »

Во-первых, из провайдера возвращайте значения через запятую:

Код: Выделить всё

public function getUsers() {
    return [
        [User::findOne(['id' => 1]), true],
        [User::findOne(['id' => 2]), true],
    ];
}
Во-вторых, сравнивайте в другую сторону:

Код: Выделить всё

self::assertEquals($result, $userService->isActive());
В третьих, для борьбы с ошибкой вместо самого юзера из провайдера передавайте id:

Код: Выделить всё

/**
 * @dataProvider getUsers
 */
public function testUserIsActive($id, $result) {
    $user = User::findOne(['id' => $id]);
    $userService = new UserService($user);
    self::assertEquals($result, $userService->isActive());
}
    	
public function getUsers() {
    return [
        [1 true],
        [2, true],
    ];
}
sergey-o90
Сообщения: 11
Зарегистрирован: 2021.05.28, 21:06

Re: При Юнит Тестах есть ошибка Call to a member function getDb() on null

Сообщение sergey-o90 »

ElisDN писал(а): 2021.10.14, 08:54 Во-первых, из провайдера возвращайте значения через запятую
Во-вторых, сравнивайте в другую сторону
В третьих, для борьбы с ошибкой вместо самого юзера из провайдера передавайте id

Спасибо вам огромное!!! Помогло!

Один вопросик: это потому, что методы, которые предоставляют данные не знают ничего о БД и контексте и поэтому сам вызов должен быть в методе тестирования?
Аватара пользователя
ElisDN
Сообщения: 5841
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: При Юнит Тестах есть ошибка Call to a member function getDb() on null

Сообщение ElisDN »

sergey-o90 писал(а): 2021.10.14, 09:00 Один вопросик: это потому, что методы, которые предоставляют данные не знают ничего о БД и контексте и поэтому сам вызов должен быть в методе тестирования?
Потому что приложение new Application создаётся только в момент _before перед каждым тестом и сразу удаляется в _after после.

А провайдер вызывается до тестов, когда этого приложения в Yii::$app ещё нет. Поэтому и ошибка, что в Yii::$app там null.
sergey-o90
Сообщения: 11
Зарегистрирован: 2021.05.28, 21:06

Re: При Юнит Тестах есть ошибка Call to a member function getDb() on null

Сообщение sergey-o90 »

ElisDN писал(а): 2021.10.14, 09:56
sergey-o90 писал(а): 2021.10.14, 09:00 Один вопросик: это потому, что методы, которые предоставляют данные не знают ничего о БД и контексте и поэтому сам вызов должен быть в методе тестирования?
Потому что приложение new Application создаётся только в момент _before перед каждым тестом и сразу удаляется в _after после.

А провайдер вызывается до тестов, когда этого приложения в Yii::$app ещё нет. Поэтому и ошибка, что в Yii::$app там null.

Понял! Спасибо большое за пояснения! :)
Ответить