Mocking Symfony Ldap :: create для модульных тестов - PullRequest
0 голосов
/ 12 октября 2018

Недавно я работал с провайдером аутентификации LDAP для MediaWiki.По-моему, я уже несколько дней пытаюсь решить эту проблему и не могу найти решение.

Контекст

Способ разработки этого плагина - разрешить настройкуиз ряда серверов, к которым мы будем подключаться.Если мы не можем подключиться к одному серверу, мы попробуем следующий ... И так далее, пока все не будут исчерпаны.

Чтобы облегчить это, в моем классе есть функция, которая перебирает серверы, пытающиеся установить соединение до тех пор, покаодин удаётся:

private function connect( LdapAuthenticationRequest $req ) {
    $dn = $this->config->get( 'BindDN' )[$req->domain];
    $pass = $this->config->get( 'BindPass' )[$req->domain];
    $servers = $this->config->get( 'Servers' )[$req->domain];
    $encryption = $this->config->get( 'EncryptionType' )[$req->domain];
    if ( false === $dn ) {
        $msgkey = 'ldapauth-attempt-bind-search';
        $bind_with = [ null, null ];
    } else {
        $msgkey = 'ldapauth-attempt-bind-dn-search';
        $bind_with = [ $dn, $pass ];
    }
    $message = new Message( $msgkey, [
        'dn' => "{$dn}@{$req->domain}",
    ] );
    $this->logger->info( $message->text() );
    foreach ( $servers as $server ) {
        if ( false === $server ) {
            continue;
        }
        $ldap = Ldap::create( 'ext_ldap', [
            'host' => $server,
            'encryption' => $encryption
        ] );
        // Attempt bind - on failure, throw an exception
        try {
            call_user_func_array( [ $ldap, 'bind' ], $bind_with );
            $this->server = $server;
            $this->encryption = $encryption;
            // log successful bind
            $msgkey = 'ldapauth-bind-success';
            $message = wfMessage( $msgkey )->text();
            $this->logger->info( $message );
            return $ldap;
        } catch ( SymException $e ) {
            if ( false === $dn ) {
                $msgkey = 'ldapauth-no-bind-search';
            } else {
                $msgkey = 'ldapauth-no-bind-dn-search';
            }
            $message = new Message( $msgkey, [
                'dn' => "{$dn}@{$req->domain}",
            ] );
            $message = $message->text();
            $this->logger->info( $message );
            $this->logger->debug( $e->getMessage() );
        }
    }

Я пытался придумать лучший способ сделать это, тот, который позволил бы мне лучше провести юнит-тестирование этого класса, но пока я рисую пробелы.

Большая часть причины, по которой я застрял в этой проблеме, заключается в том, что LDAP-адаптер Symfony по существу жестко связан с моим кодом, так как вызов connect является статическим вызовом в кодовой базе Symfony.то есть я не могу передать соединитель экземпляр некоторого описания, которое затем попыталось бы установить соединение.Я просто обертываю Ldap::create своей собственной оболочкой подключения, возможно?

1 Ответ

0 голосов
/ 19 октября 2018

Так как вы используете Symfony, я думаю, что вам лучше всего было бы внедрить LDap объект, используя инъекцию зависимостей фреймворка.Однако я не эксперт в Symfony.Итак, как простой взлом, я бы сделал это так:

  private function connect($req)
    {
        $dn = $this->config->get('BindDN')[$req->domain];
        $pass = $this->config->get('BindPass')[$req->domain];
        $servers = $this->config->get('Servers')[$req->domain];
        $encryption = $this->config->get('EncryptionType')[$req->domain];
        if (false === $dn) {
            $msgkey = 'ldapauth-attempt-bind-search';
            $bind_with = [null, null];
        } else {
            $msgkey = 'ldapauth-attempt-bind-dn-search';
            $bind_with = [$dn, $pass];
        }
        $message = new Message($msgkey, [
            'dn' => "{$dn}@{$req->domain}",
        ]);
        $this->logger->info($message->text());
        foreach ($servers as $server) {
            if (false === $server) {
                continue;
            }
            $ldap = $this->createLDAPObject($server, $encryption);
            // Attempt bind - on failure, throw an exception
            try {
                call_user_func_array([$ldap, 'bind'], $bind_with);
                $this->server = $server;
                $this->encryption = $encryption;
                // log successful bind
                $msgkey = 'ldapauth-bind-success';
                $message = wfMessage($msgkey)->text();
                $this->logger->info($message);
                return $ldap;
            } catch (SymException $e) {
                if (false === $dn) {
                    $msgkey = 'ldapauth-no-bind-search';
                } else {
                    $msgkey = 'ldapauth-no-bind-dn-search';
                }
                $message = new Message($msgkey, [
                    'dn' => "{$dn}@{$req->domain}",
                ]);
                $message = $message->text();
                $this->logger->info($message);
                $this->logger->debug($e->getMessage());
            }
        }
    }

    /**
     * @param $server
     * @param $encryption
     * @return mixed
     */
    public function createLDAPObject($server, $encryption)
    {
        return Ldap::create('ext_ldap', [
            'host' => $server,
            'encryption' => $encryption
        ]);
    }

Затем вы можете смоделировать метод-член createLDAPObject вместо насмешки над статическим методом Ldap::create, что должно быть проще.

Однако я бы порекомендовал вам провести рефакторинг вашего кода, чтобы он был более читабельным и тестируемым.

1 - Прежде всего, call_user_func_array() не очень удобен для тестирования, и я думаю, что вашТребования здесь не слишком динамичны, поэтому вы можете заменить эту строку на $ldap->bind($bind_with[0],$bind_with[1]);

2 - Ваш метод connect слишком велик для тестирования.Пожалуйста, прочитайте о Запахи кода - длинные методы

3 - Метод может быть реорганизован в меньшую версию путем отделения представления от логики.Например, вы получаете объект Message для получения текста из $msgkey просто для его регистрации, что не способствует удобочитаемости кода и способности к тестированию.

Это мои первые мысли овещь:)

Удачного кодирования и тестирования:)

...