Я пытаюсь протестировать свою php cms, и у меня много вопросов о том, почему и как:
- официальная политика НЕ для тестирования защищенных / частных методов
но тогда речь идет о функциональном / поведенческом тестировании, а не о модульном тестировании
- разработка phpunit прекратила поддержку тестирования базы данных все время назад; sth они назвали это
dbunit
, если я правильно помню
, в результате нам действительно нужно создавать сложные тестовые классы для управления базой данных, или потому что эти классы уже существуют в такой обширной работе, как моя, мы должны здесь и там существовали методы из других классов, которые облегчают управление базой данных, поэтому тестируемая система фактически помогает тестирующему ПО в тесном взаимодействии друг с другом
- Говорят, что тестирование на самом деле вызывает ваш код еще до того, как написать его с помощью вашей потрясающей командной строки и шаг за шагом перейти к своей цели
, но если ваше тестирование код нацелен на более функциональный подход, я могу назвать свой в процессе разработки любым другим способом, даже из командной строки, и отладить его, отправив вывод в php журнал с error_log
.
Сказав, что я избавляю себя от необходимости писать 100 строк кода + более 100 строк тестовых файлов, изменение 100 строк кода + изменение более 100 строк теста файлы и так далее ....
Если мы добавим выше все аргументы о том, что не нужно тестировать защищенные / закрытые члены, мы закончим простым вопросом: зачем эта возня с модульным тестированием частных / защищенных методов что может иметь длинную цепочку внутренних вызовов, когда есть гораздо более простые методы тестирования, пока мы кодируем?
Все приведенное выше введение кажется мне необходимым, чтобы читатель понял, о чем я спрашиваю:
Учитывая следующий конкретный c метод, можете ли вы предложить лучший подход (модульного?) Тестирования?
1 Тестируемый метод
Файл /home/test/server/auth/Auth.php
namespace g3\auth;
use g3\Singleton;
use g3\TokenFactory;
use g3\Registry;
use g3\Header;
use g3\Session;
use g3\Lang;
use g3\Utils;
use g3\mail\MailClient;
use Firebase\JWT;
class Auth {
/** @var AuthToken $token The AuthToken of this class */
protected $token;
/** @var PDO $dbh The PDO handler to the database */
protected $dbh;
...............
...............
/**
* Called by user/admin during the registration.
*
* We use argument '$params' to handle the additional fields that we added at
* table 'profiles' (beyond, 'id', 'emai', 'password', 'isactive' and 'dt').
* An example for '$params': array('first_name' => "John", 'second_name' => "Doe").
* The available fields:
* - 'title',
* - 'fullname',
* - 'first_name',
* - 'second_name',
* - 'username',
* - 'address1',
* - 'address2',
* - 'zip1',
* - 'zip2',
* - 'tel',
* - 'mobile',
* - 'fax',
* - 'city',
* - 'state',
* - 'country',
* - 'birth',
* - 'language',
* - 'currency',
* - 'img',
* - 'capacity_kb'.
*
* Two modes of call:
* -by user: addUser($email, $password, $params, $name),
* -by admin: addUser($email, $password, $params, $name, true).
*
* In admin mode no request is added or email is sent.
*
* If useradd succeeds but profile fails to be inserted in table 'profiles'
* then return array contains key 'message' although key 'error' remains
* 'false' (registration proceeds).
*
* @param string $email
* @param string $password
* @param string[] $params Data for table 'profiles'
* @param boolean $admin True to bypass activation process
*
* @return A hash array with keys 'error', 'message' and if successful, 'uid'
*/
protected function addUser($email, $password, $params = array(), $name = '', $admin = false) {
$return['error'] = true;
$query = $this->dbh->prepare("INSERT INTO {$this->token->get('table_users')} (isactive) VALUES (0)");
if (!$query->execute()) {
$return['message'] = $this->getLang()["system_error"] . " #03";
return $return;
}
$uid = $this->dbh->lastInsertId();
$email = \htmlentities(\strtolower($email));
if (((int)$this->token->get('suppress_activation') != 1) && !$admin) {
$addRequest = $this->addRequest($uid, $email, "activation", $name);
if ($addRequest['error'] == 1) {
$query = $this->dbh->prepare("DELETE FROM {$this->token->get('table_users')} WHERE id = ?");
$query->execute(array($uid));
$return['message'] = $addRequest['message'];
return $return;
}
$isactive = 0;
} else {
$isactive = 1;
}
$password = $this->getHash($password);
$query = $this->dbh->prepare("UPDATE {$this->token->get('table_users')} SET email = ?, password = ?, isactive = ? WHERE id = ?");
if (!$query->execute(array($email, $password, $isactive, $uid))) {
$query = $this->dbh->prepare("DELETE FROM {$this->token->get('table_users')} WHERE id = ?");
$query->execute(array($uid));
$return['message'] = $this->getLang()["system_error"] . " #04";
return $return;
}
if (!\is_array($params))
$params = array();
if(($r = $this->addProfile($uid, $params)) !== true)
$return['message'] = $r['message'];
$return['error'] = false;
$return['uid'] = $uid;
return $return;
}
.............
.............
}
База данных - это SQLite.
Очевидно, что вызывается множество других методов class Auth
:
Auth::addUser
| | | |
v | | |
Auth::getLang
| | |
v | |
Auth::addRequest
| |
v |
Auth::getHash
|
v
Auth::addProfile
Также используется ряд других классов :
class Auth
| | |
v | |
Auth::token is a AuthToken: contains parameters supporting the
authentication system like table names, database path etc.
| |
v |
class Lang: contains parameters that lead to language specific
messages
|
v
Auth::dbh is a database connection returned by DbHandler::getHandler
class DbHandler: manages the database
Вы можете пропустить следующие части и прочитать «5. Напишите несколько тестов "
2 Установка Composer
просто скачайте локальную composer.phar
сборку a composer.json
: меня не волнует автозагрузчик composer, так как у меня есть мой, и я загружаю его туда из своей подпапки /home/test/server/g3
Я не используйте vendor
, но только для разработки пакетов, все производственное программное обеспечение, включая мою g3
framework, развернуто в подпапке /home/test/server
в отдельных подпапках с настраиваемым автозагрузчиком
/ home / test / composer. json
{
"autoload": {
"psr-4": {
"": "server"
}
},
"require-dev": {
"mockery/mockery": "=1.3.1",
"phpunit/phpunit": "=6.5.14",
"phpunit/php-invoker": "=1.1.4",
"gealex/doublit": "=2.1.5",
"phpspec/prophecy": "=1.10.3"
}
}
/ home / test / vendor / autoloader. php
<?php
// my autoloader
require_once("/home/test/server/g3/ClassLoader.php");
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit1e0ee11cc0a18a5af0d236383dd8a888::getLoader();
3 Настройте phpunit
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="/home/test/vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
verbose="true">
<testsuites>
<testsuite name="Root">
<directory suffix="Test.php">../../tests/server/root</directory>
</testsuite>
<testsuite name="Core">
<directory suffix="Test.php">../../tests/server/core</directory>
</testsuite>
<testsuite name="Auth">
<directory suffix="Test.php">../../tests/server/auth</directory>
</testsuite>
<testsuite name="mail">
<directory suffix="Test.php">../../tests/server/mail</directory>
</testsuite>
</testsuites>
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">server</directory>
</whitelist>
</filter>
<php>
<var name="skip_mail_integration_tests" value="1"/>
<var name="skip_auth_integration_tests" value="1"/>
<var name="domain" value="4f4d4ebc35f1.eu.ngrok.io"/>
<var name="mailTo" value="john.doe@gmail.com"/>
</php>
</phpunit>
4 Расширьте PHPUnit \ Framework \ TestCase
Сначала давайте расширим PHPUnit\Framework\TestCase
с помощью /home/test/tests/server/CustomTestCase.php
, что
поддерживает Prophecy
и Mockery
содержит служебные методы callMethod
, getProperty
и setProperty
который может получить доступ к закрытым / защищенным членам
инициализирует \g3\Registry
реальными \g3\Token
значениями, поступающими из json файлов
<?php
declare(strict_types=1);
use Mockery\Adapter\Phpunit\MockeryTestCase;
use PHPUnit\Framework\TestCase;
/**
* runTestsInSeparateProcesses
*/
class CustomTestCase extends MockeryTestCase {
protected $prophet;
// returns the call to private/protected methods
public static function callMethod($obj, $name, array $args) {
$class = new \ReflectionClass($obj);
$method = $class->getMethod($name);
$method->setAccessible(true);
return $method->invokeArgs($obj, $args);
}
// returns private/protected properties
public static function getProperty($obj, $name){
$r = new ReflectionObject($obj);
$p = $r->getProperty($name);
$p->setAccessible(true);
return $p->getValue($obj);
// alternative syntax with closures
//$cls = \Closure::bind(function() use ($name){return $this->{$name};}, $obj, \get_class($obj));
//return $cls();
}
// sets a value to a private/protected property
public static function setProperty($object, $property, $value){
$ref = new \ReflectionClass($object);
$ref_prop = $ref->getProperty($property);
$ref_prop->setAccessible(true);
$ref_prop->setValue($object, $value);
}
public static function setUpBeforeClass(){
Mockery::globalHelpers();
}
public static function tearDownAfterClass(){
}
protected function setup() {
$this->prophet = new \Prophecy\Prophet;
}
protected function tearDown() {
$this->prophet->checkPredictions();
Mockery::close();
}
}
5 Напишите несколько тестов
Файл /home/test/tests/server/g3/auth/AuthTest.php
<?php
declare(strict_types=1);
require_once(__DIR__ . '/../CustomTestCase.php');
/**
* runTestsInSeparateProcesses
*/
class AuthTest extends CustomTestCase {
protected $tokens;
public static function setUpBeforeClass(){
parent::setUpBeforeClass();
// tokens initialize the g3 framework and these contain full data
// from json files; access them like:
// \g3\Registry::getInstance()->getToken('g3\auth\AuthToken') etc.
static::callMethod(\g3\Dispatcher::getInstance(), 'tokenInit', array());
}
public static function tearDownAfterClass(){
parent::tearDownAfterClass();
\g3\Registry::getInstance()->destroy();
}
/**
* Creates mocked constructor argument objects before each test.
* These tokens do not contain data read from json files; dummy tokens.
* Accessible through $this->tokens.
*/
protected function setup() {
parent::setup();
$resolverToken = $this->getMockBuilder('\g3\ResolverToken')
->disableOriginalConstructor()
->getMock();
$requestToken = $this->getMockBuilder('\g3\RequestToken')
->disableOriginalConstructor()
->getMock();
$authToken = $this->getMockBuilder('\g3\auth\AuthToken')
->disableOriginalConstructor()
->getMock();
$accountToken = $this->getMockBuilder('\g3\AccountToken')
->disableOriginalConstructor()
->getMock();
$dbh = $this->getMockBuilder('\g3\DbHandler')
->disableOriginalConstructor()
->getMock();
$lang = $this->getMockBuilder('\g3\Lang')
->disableOriginalConstructor()
->getMock();
$session = $this->getMockBuilder('\g3\Session')
->disableOriginalConstructor()
->getMock();
$this->tokens = array('accountToken' => $accountToken, 'resolverToken' => $resolverToken, 'requestToken' => $requestToken, 'authToken' => $authToken, 'dbh' => $dbh, 'lang' => $lang, 'session' => $session);
}
/**
* Deletes mocked objects stored at $this->tokens after each test.
*/
protected function tearDown() {
parent::tearDown();
$this->tokens = null;
}
/**
* Prints a message on CLI
*/
public function out($msg){
$msg = \str_replace(array('test_', '_', "\n"), array('', ' ', ":\n"), $msg);
fwrite(STDOUT, $msg);
}
/**
* Adds an inactive user. It uses real tokens.
*/
public function helper_addUserInactive($arr) {
// AuthToken is not stored in Registry & not synchronized
\g3\TokenFactory::getInstance()->synchronize($arr['authToken'], 'r');
$test = $this->getMockBuilder('\g3\auth\Auth')
->setConstructorArgs(array($arr['resolverToken'], $arr['requestToken'], $arr['authToken'], $arr['accountToken'], $arr['dbh']))
->setMethods(['addRequest', 'getHash'])
->getMock();
$test->expects($this->exactly(1))
->method('addRequest')
->will($this->returnValue(array('error' => false)));
$test->expects($this->exactly(1))
->method('getHash')
->will($this->returnValue('123'));
$token = static::getProperty($test, 'token');
$token->set('suppress_activation', 0);
$profile = array('first_name' => 'John', 'second_name' => 'Doe', 'username' => 'John', 'address1' => 'White House, Washington D.C.', 'country' => 'USA');
// call 'addUser'
$r = static::callMethod($test, 'addUser', array($arr['to'], '123', $profile, 'John'));
$users = $arr['authToken']->get('table_users');
$profiles = $arr['authToken']->get('table_profiles');
return array(
'dbh' => $arr['dbh'],
'user' => array('id' => $r['uid'], 'email' => $arr['to'], 'password' => '123', 'role' => 'guest', 'isactive' => '0'),
'profile' => $profile,
'tables' => array('users' => $arr['authToken']->get('table_users'), 'profiles' => $arr['authToken']->get('table_profiles'), 'requests' => $arr['authToken']->get('table_requests'))
);
}
/**
* Adds an active user. It uses real tokens.
*/
public function helper_addUserActive($arr) {
// AuthToken is not stored in Registry & not synchronized
\g3\TokenFactory::getInstance()->synchronize($arr['authToken'], 'r');
$test = $this->getMockBuilder('\g3\auth\Auth')
->setConstructorArgs(array($arr['resolverToken'], $arr['requestToken'], $arr['authToken'], $arr['accountToken'], $arr['dbh']))
->setMethods(['addRequest', 'getHash'])
->getMock();
$test->expects($this->never())
->method('addRequest');
$test->expects($this->exactly(1))
->method('getHash')
->will($this->returnValue('123'));
$token = static::getProperty($test, 'token');
$token->set('suppress_activation', 1);
$profile = array('first_name' => 'John', 'second_name' => 'Doe', 'username' => 'John', 'address1' => 'White House, Washington D.C.', 'country' => 'USA');
// call 'addUser'
$r = static::callMethod($test, 'addUser', array($arr['to'], '123', $profile, 'John'));
$users = $arr['authToken']->get('table_users');
$profiles = $arr['authToken']->get('table_profiles');
return array(
'dbh' => $arr['dbh'],
'user' => array('id' => $r['uid'], 'email' => $arr['to'], 'password' => '123', 'role' => 'guest', 'isactive' => '1'),
'profile' => $profile,
'tables' => array('users' => $arr['authToken']->get('table_users'), 'profiles' => $arr['authToken']->get('table_profiles'), 'requests' => $arr['authToken']->get('table_requests'))
);
}
/**
* Adds an active user as admin. It uses real tokens.
*/
public function helper_adminAddsUserActive($arr) {
// AuthToken is not stored in Registry & not synchronized
\g3\TokenFactory::getInstance()->synchronize($arr['authToken'], 'r');
$test = $this->getMockBuilder('\g3\auth\Auth')
->setConstructorArgs(array($arr['resolverToken'], $arr['requestToken'], $arr['authToken'], $arr['accountToken'], $arr['dbh']))
->setMethods(['addRequest', 'getHash'])
->getMock();
$test->expects($this->never())
->method('addRequest');
$test->expects($this->exactly(1))
->method('getHash')
->will($this->returnValue('123'));
$token = static::getProperty($test, 'token');
$token->set('suppress_activation', 0);
$profile = array('first_name' => 'John', 'second_name' => 'Doe', 'username' => 'John', 'address1' => 'White House, Washington D.C.', 'country' => 'USA');
// call 'addUser'
$r = static::callMethod($test, 'addUser', array($arr['to'], '123', $profile, 'John', true));
$users = $arr['authToken']->get('table_users');
$profiles = $arr['authToken']->get('table_profiles');
return array(
'dbh' => $arr['dbh'],
'user' => array('id' => $r['uid'], 'email' => $arr['to'], 'password' => '123', 'role' => 'guest', 'isactive' => '1'),
'profile' => $profile,
'tables' => array('users' => $arr['authToken']->get('table_users'), 'profiles' => $arr['authToken']->get('table_profiles'), 'requests' => $arr['authToken']->get('table_requests'))
);
}
/**
* Inserts a user & profile without the call to any `Auth` method.
* It uses real tokens.
*/
public function helper_insertUser($arr, $active = '0') {
// AuthToken is not stored in Registry & not synchronized
\g3\TokenFactory::getInstance()->synchronize($arr['authToken'], 'r');
$users = $arr['authToken']->get('table_users');
$profiles = $arr['authToken']->get('table_profiles');
$requests = $arr['authToken']->get('table_requests');
// table 'users'
$time = \time();
$query = $arr['dbh']->getHandler()->prepare("INSERT INTO {$users} (email, password, isactive, dt) VALUES (?, ?, ?, ?)");
$query->execute(array($arr['to'], '123', $active, $time));
$uid = $arr['dbh']->getHandler()->lastInsertId();
return array(
'dbh' => $arr['dbh'],
'user' => array('id' => $uid, 'email' => $arr['to'], 'password' => '123', 'role' => 'guest', 'isactive' => $active),
'tables' => array('users' => $users, 'profiles' => $profiles, 'requests' => $requests)
);
}
/**
* Deletes user from tables `users`, `profiles` and `requests`.
* `$arr` is the return of `::test_helper_addUserInactive` or
* `::test_helper_addUserActive`.
*/
public function helper_deleteAddedUser($arr) {
$users = $arr['tables']['users'];
$profiles = $arr['tables']['profiles'];
$requests = $arr['tables']['requests'];
$query = $arr['dbh']->getHandler()->prepare("DELETE FROM {$users} WHERE id = ?");
$query->execute(array($arr['user']['id']));
$query = $arr['dbh']->getHandler()->prepare("DELETE FROM {$profiles} WHERE uid = ?");
$query->execute(array($arr['user']['id']));
$query = $arr['dbh']->getHandler()->prepare("DELETE FROM {$requests} WHERE uid = ?");
$query->execute(array($arr['user']['id']));
}
/**
* Helper that returns real tokens of g3 platform.
* @group integration_email
* @group test
*/
public function test_helper_construct_with_real_tokens() {
$systemToken = \g3\Registry::getInstance()->getToken('g3\SystemToken');
$accountToken = \g3\Registry::getInstance()->getToken('g3\AccountToken');
$lang = new \g3\Lang(ROOT . "/server/g3/auth/language", $accountToken->get('site', 'language'));
$exceptionToken = \g3\Registry::getInstance()->getToken('g3\ExceptionToken');
$dbh = new \g3\DbHandler('sqlite', 'db_auth', $accountToken, $exceptionToken);
// AuthToken is not stored in Registry & not synchronized
$authToken = \g3\TokenFactory::getInstance()->getToken('g3\auth\AuthToken', null, array('registry' => \g3\Registry::getInstance(), 'dbh' => $dbh));
\g3\TokenFactory::getInstance()->synchronize($authToken, 'r');
$requestToken = \g3\Registry::getInstance()->getToken('g3\RequestToken');
$resolverToken = \g3\Registry::getInstance()->getToken('g3\ResolverToken');
$session = \g3\Session::getInstance();
$to = $GLOBALS['mailTo'];
$this->assertTrue(true);
return array('systemToken' => $systemToken, 'accountToken' => $accountToken, 'resolverToken' => $resolverToken, 'requestToken' => $requestToken, 'authToken' => $authToken, 'exceptionToken' => $exceptionToken, 'dbh' => $dbh, 'lang' => $lang, 'session' => $session, 'to' => $to);
}
// !!!WAIT WHAT THE HELL!!!
// !!!WE DIDN'T EVEN BEGIN TO TEST!!!
/*
* ===============
* Auth::addUser()
* ===============
*/
/**
* @depends test_helper_construct_with_real_tokens
*/
public function test_addUser_for_misspelled_table_users($arr) {
$this->out(__METHOD__ . "\n");
// AuthToken is not stored in Registry & not synchronized
\g3\TokenFactory::getInstance()->synchronize($arr['authToken'], 'r');
$test = $this->getMockBuilder('\g3\auth\Auth')
->setConstructorArgs(array($arr['resolverToken'], $arr['requestToken'], $arr['authToken'], $arr['accountToken'], $arr['dbh']))
->setMethods(null)
->getMock();
$token = static::getProperty($test, 'token');
$token->set('table_users', 'user');
// call 'addUser'
$this->expectException(PDOException::class);
$r = static::callMethod($test, 'addUser', array($arr['to'], '123', array(), 'John'));
echo "\n";
}
/**
* @depends test_helper_construct_with_real_tokens
*/
public function test_addUser_updates_tables_users_profiles($tokens) {
$this->out(__METHOD__ . "\n");
$arr = $this->helper_addUserInactive($tokens);
$users = $arr['tables']['users'];
$profiles = $arr['tables']['profiles'];
// query table 'users'
$query = $arr['dbh']->getHandler()->prepare("SELECT email, role, password, isactive FROM $users WHERE id = ?");
$query->execute(array($arr['user']['id']));
$row = $query->fetch(\PDO::FETCH_ASSOC);
$this->assertSame($arr['user']['email'], $row['email']);
$this->assertSame($arr['user']['role'], $row['role']);
$this->assertSame($arr['user']['password'], $row['password']);
$this->assertSame($arr['user']['isactive'], $row['isactive']);
// query table 'profiles'
$query = $arr['dbh']->getHandler()->prepare("SELECT first_name, second_name, username, address1 FROM $profiles WHERE uid = ?");
$query->execute(array($arr['user']['id']));
$row = $query->fetch(\PDO::FETCH_ASSOC);
$this->assertSame($arr['profile']['first_name'], $row['first_name']);
$this->assertSame($arr['profile']['second_name'], $row['second_name']);
$this->assertSame($arr['profile']['username'], $row['username']);
$this->assertSame($arr['profile']['address1'], $row['address1']);
// delete entries in tables
$this->test_helper_deleteAddedUser($arr);
echo "\n";
}
/**
* @depends test_helper_construct_with_real_tokens
*/
public function test_addUser_updates_tables_users_profiles_with_supress_activation($tokens) {
$this->out(__METHOD__ . "\n");
$arr = $this->helper_addUserActive($tokens);
$users = $arr['tables']['users'];
$profiles = $arr['tables']['profiles'];
// query table 'users'
$query = $arr['dbh']->getHandler()->prepare("SELECT email, role, password, isactive FROM $users WHERE id = ?");
$query->execute(array($arr['user']['id']));
$row = $query->fetch(\PDO::FETCH_ASSOC);
$this->assertSame($arr['user']['email'], $row['email']);
$this->assertSame($arr['user']['role'], $row['role']);
$this->assertSame($arr['user']['password'], $row['password']);
$this->assertSame($arr['user']['isactive'], $row['isactive']);
// query table 'profiles'
$query = $arr['dbh']->getHandler()->prepare("SELECT first_name, second_name, username, address1 FROM $profiles WHERE uid = ?");
$query->execute(array($arr['user']['id']));
$row = $query->fetch(\PDO::FETCH_ASSOC);
$this->assertSame($arr['profile']['first_name'], $row['first_name']);
$this->assertSame($arr['profile']['second_name'], $row['second_name']);
$this->assertSame($arr['profile']['username'], $row['username']);
$this->assertSame($arr['profile']['address1'], $row['address1']);
// delete entries in tables
$this->test_helper_deleteAddedUser($arr);
echo "\n";
}
/**
* @depends test_helper_construct_with_real_tokens
*/
public function test_addUser_updates_tables_users_profiles_for_admin($tokens) {
$this->out(__METHOD__ . "\n");
$arr = $this->helper_adminAddsUserActive($tokens);
$users = $arr['tables']['users'];
$profiles = $arr['tables']['profiles'];
// query table 'users'
$query = $arr['dbh']->getHandler()->prepare("SELECT email, role, password, isactive FROM $users WHERE id = ?");
$query->execute(array($arr['user']['id']));
$row = $query->fetch(\PDO::FETCH_ASSOC);
$this->assertSame($arr['user']['email'], $row['email']);
$this->assertSame($arr['user']['role'], $row['role']);
$this->assertSame($arr['user']['password'], $row['password']);
$this->assertSame($arr['user']['isactive'], $row['isactive']);
// query table 'profiles'
$query = $arr['dbh']->getHandler()->prepare("SELECT first_name, second_name, username, address1 FROM $profiles WHERE uid = ?");
$query->execute(array($arr['user']['id']));
$row = $query->fetch(\PDO::FETCH_ASSOC);
$this->assertSame($arr['profile']['first_name'], $row['first_name']);
$this->assertSame($arr['profile']['second_name'], $row['second_name']);
$this->assertSame($arr['profile']['username'], $row['username']);
$this->assertSame($arr['profile']['address1'], $row['address1']);
// delete entries in tables
$this->test_helper_deleteAddedUser($arr);
echo "\n";
}
Я только что тестировал то, что знал с самого начала - несколько месяцев go - он работал так, как я мог отправлять запросы GET или POST и с введенным error_log
У меня есть производственный безошибочный код, обходящий все теории модульного тестирования.
Также эти тесты подвержены ошибкам, если кто-то начинает возиться с методом тестирования, они начинают создавать код ошибки из тестового файла; в этом случае вам придется отлаживать тесты, которые пытаются проверить ваш код!
С моей точки зрения, я начинаю верить, что модульное тестирование - отличный способ потратить потерять ваше время. Я понимаю ваш аргумент, что это не модульное тестирование, поэтому я заменить protected
на public
, это что-то исправляет? Интересно, может ли кто-нибудь доказать, что я неправ? Каков тогда ваш подход?