Подделка условий ошибки в библиотеке mysqli


У меня есть множество PHP-скриптов, которые используют набор функций mysqli для доступа к базе данных. Я написал эти сценарии для обработки различных условий ошибок (например, mysqli_stmt_execute, возвращающих false).

Существует ли простой способ подделать эти условия ошибки, чтобы проверить, что выходные данные, полученные пользователем, соответствуют этим условиям?

Author: rdlowrey, 2012-07-27

4 answers

Если вы используете классы mysqli.

Например:

<?php
     $mysqli = new mysqli("localhost", "user", "password", "db");
     $query = "INSERT INTO some_table (some_field) VALUES ('some_vale')";
     $stmt = $mysqli->prepare($query);
     if (false === $stmt->execute()) {
         echo "Oops! some_value for same_field in some_table returned false";
     }

Издевайтесь над классами и выполняйте инструкцию перезаписи.

<?php
    class my_mysqli extends mysqli
    {
        public function prepare ($query)
        {
            return new my_mysqli_stmt();
        }

    }

    class my_mysqli_stmt extends mysqli_stmt {
        public function execute ()
        {
            return false;
        }
    }

Все, что вам нужно изменить, чтобы каждый метод выполнения возвращал значение false, это:

<?php
     $mysqli = new my_mysqli("localhost", "user", "password", "db");

Если вы используете функции вместо

Например:

<?php
     $mysqli = mysqli_connect("localhost", "user", "password", "db");
     $query = "INSERT INTO some_table (some_field) VALUES ('some_vale')";
     $stmt = mysqli_prepare($mysqli, $query);
     if (false === mysqli_stmt_execute($stmt)) {
         echo "Oops! some_value for same_field in some_table returned false";
     }

Патч обезьяны в пространстве имен php>=5.3

<?php
    namespace my_faking_namespace {
        function mysqli_stmt_execute($stmt) 
        {
            return false;    
        }

        $mysqli = mysqli_connect("localhost", "user", "password", "db");
        $query = "INSERT INTO some_table (some_field) VALUES ('some_vale')";
        $stmt = mysqli_prepare($mysqli, $query);
        if (false === mysqli_stmt_execute($stmt)) {
            echo "Oops! some_value for same_field in some_table returned false";
        }
    }

Ваш скрипт будет вызывать my_faking_namespace\mysqli_stmt_execute() вместо версии php.

Примечание: это не будет работать, если вы вызываете такие функции, как \mysqli_stmt_execute(), поскольку эта версия явно вызывает глобальное пространство имен.

Не столь простые альтернативы для целей завершения

Они изменяют функции на уровне стека вызовов, изменяя php внутренне с помощью пользовательских модулей расширения (требуется установка).

  • Расширенный отладчик PHP имеет override_function() и rename_function()
  • ранкит имеет runkit_function_copy, runkit_function_redefine, runkit_function_remove, runkit_function_rename и может измениться просто обо всем, что вы пожелаете.

НДЖой!

 8
Author: nickl-, 2012-08-26 06:32:45

Если вы ищете автоматизированное тестирование, лучший способ (с PHP) - это PHPUnit.

С помощью PHPUnit вы можете писать модульные тесты (в частности, утверждения), которые позволяют проверить, что выходные данные, полученные пользователем, соответствуют любым различным условиям.

 1
Author: bitfox, 2012-08-25 23:03:40

Если вы не находитесь в производственной среде, лучший способ сделать это - изменить различные параметры базы данных в вашем PHP.

  • Измените пароль базы данных, чтобы узнать, как вы обрабатываете ошибки подключения
  • Измените структуру таблиц, чтобы увидеть, как вы справляетесь с ошибками запроса
  • Попробуйте посмотреть, что происходит со специальными символами (например: буква) в ваших запросах
 0
Author: Tchoupi, 2012-07-27 12:16:50

Возможно, вы задаете неправильный вопрос: почему ваша основная бизнес-логика зависит от сторонних библиотек/API? Вы слышали о так называемой луковой архитектуре? Разделение вашего приложения в большей степени по этим направлениям - домен, бизнес, инфраструктура/тесты - значительно упрощает тестирование того, что не изменится: вашей бизнес-логики.

Однако, поскольку PHP является динамическим типизированным языком, насмешки, по сути, бесплатны. До тех пор, пока вы используете функции OO, а не глобальные функции, все, что вам нужно для создания тестируемого кода, - это способ внедрить в ваш код поддельный дескриптор базы данных. Отличный способ - добавить параметр $db в ваши функции/методы. Что-то тривиальное вроде этого:

function updateStuff($rowIds, $newValues, $db) { ... }

Затем в ваших модульных тестах, которые охватывают updateStuff, передайте макет объекта в качестве параметра $db.

 0
Author: EthanB, 2012-08-26 17:35:41