Автоматизированное тестирование с использованием Zend Framework

Метки: веб-разработка, модульное тестирование, zend framework

Автоматизоване тестування з використанням Zend Framework Автоматизоване тестування з використанням Zend Framework
Automated Testing Using Zend Framework Automated Testing Using Zend Framework

Автоматизированное тестирование вашего веб-приложения является важным шагом для уверенности в качестве и отсутствии ухудшения, при внесении изменений в ваше приложение. С тестирующим фреймворком от Zend Framework (построен с PHPUnit) вы можете составить блоки тестовых случаев для вашего веб-приложения без малейших препираний.
В этой статье предоставлена вся базовая информация, которая понадобится вам при написании автоматизированных тестов для приложений Zend Framework.

А теперь, давайте перейдем к делу
В нижеприведенном примере я буду использовать действительный контроллер одного из моих проектов. Этот контроллер управляет действиями, связанными с учетными записями, такими как вход, выход, регистрация и подтверждение. Мы будем использовать тестовую базу данных со схемой, которая клонирует нашу базу данных продукции, с Doctrine для управления ORM (прости, Zend_Db :() Я предполагаю, что вы используете вышеуказанную схему проектов Zend Framework (1.6+), и что вы знакомы с Zend_Config и используете плагин контроллера Initializer (созданный по умолчанию, если вы используете Zend Studio for Eclipse 6.1).

Подготовка вашего приложения
Первым шагом для создания автоматизированного тестирования является правильная подготовка окружения и настроек вашего приложения. В зависимости от ваших установок, это может включать установку глобальных переменных, изменение связей базы данных, или перенастройка путей. К счастью для нас, это легко делается с помощью у Zend_Config и плагина контроллера Initializer.
Zend_Config позволяет назначать «разделы», которые могут наследоваться из другого раздела. Это позволяет менять конфигурацию для разных условий без дублирования установок в разных файлах (и таким образом помогает нам убедиться, что мы ничего не забыли!). В нашем тестовом проекте нам понадобится изменить только строку соединения с базой данных, значит, мы используем тестовую базу данных.
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<config>
 
<production>
  <db>
    <dsn>mysql://dbowner:password@localhost/maindb</dsn>
    <attributes>
        <model_loading>conservative</model_loading>
    </attributes>
  </db>
</production>
<test extends="production">
  <db>
    <dsn>mysql://dbowner:password@localhost/maindb_test</dsn>
  </db>
</test>
</config>

Обратите внимание, как мы можем наследовать дочерние атрибуты: хотя мы назначили узел, нам не потребовалось назначать все, что ниже него.
Сейчас, когда все наши настройки в порядке, нам необходимо что-то для управления ими, а также выключение, основанного на среде, в которой мы работаем. Это роль нашего плагина Initializer, который принимает среду для инициализации как параметр конструктора.

Простой пример
Давайте начнем с простого фреймворка тестирования контроллера. Если вы используете Zend Studio для Eclipse, вы можете легко создать эту структуру щелчком правой кнопки на контроллере в PHP Explorer, перейти в New > Zend Framework Item и затем выбрать Zend Controller Test Case. Потом просто убедитесь, что контроллер, который вы хотите протестировать, выбран, и нажмите finish.
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
require_once 'application/Initializer.php';
require_once 'application/default/controllers/IndexController.php';
 
class AccountControllerTest extends Zend_Test_PHPUnit_ControllerTestCase {
 
    /**
     * Подготовка среды перед запуском теста
     */
    protected function setUp() {
        $this->bootstrap = array ($this, 'appBootstrap' );
        parent::setUp ();
        // TODO Auto-generated FooControllerTest::setUp()
    }
 
    /**
     * Подготовка среды перед запуском теста
     */
    public function appBootstrap() {
        $this->frontController->registerPlugin ( new Initializer( 'test' ) );
    }
 
    /**
     * Очистка среды после запуска теста
     */
    protected function tearDown() {
        // TODO Автогенерация FooControllerTest::tearDown()
        parent::tearDown ();
    }
 
    /**
     * Создание условий теста
     */
    public function __construct() {
        // TODO Автогенерация конструктора
    }
 
    /**
     * Тесты FooController->barAction()
     */
    public function testIndexAction() {
        // TODO Автосгенерированный
               // FooControllerTest->testBarAction()
        $this->dispatch ( '/index/index' );
        $this->assertController ( 'index' );
        $this->assertAction ( 'index' );
    }
}

Как вы можете видеть, в строке 21 мы используем наш инициализатор для установки тестовой среды до запуска тестов. До запуска каждого теста, PHPUnit будет вызывать наш метод setup(), который был запрограммирован на запуск нашего метода appBootstrap. Это гарантирует нам, что мы используем чистую конфигурацию и среду перед каждым тестом, так же, как если бы каждый тест был отдельным процессом. Когда все тесты пройдены, вызывается метод tearDown(). Это место для любого кода, который удаляет ресурсы или сбрасывает любые изменения, которые могли сделать тесты. Нам пригодится это позже в наших продвинутых примерах.
Строка 45 содержит скелет тестового условия, который будет обеспечивать, что диспетчеризация результатов ‘/index/index’ в контроллере названном ‘index’ и действии под названием ‘index’, были запущены последними. Это может казаться тривиальным, но это поможет обнаружить ошибки связанные с вашими контроллерами. Если будет обнаружено непредусмотренное исключение, утверждение контроллера будет ошибочным, поскольку он будет запущен последним.

Запуск ваших тестов
Чтобы статья была сфокусирована, я решил удалить этот раздел и рассказать только о написании тестов. Если вам нужна помощь в создании Блоков Теста и запуске тестов с командной строки, смотрите документацию PHPUnit, особенно раздел о запуске тестов с командной строки и организации блоков теста.
Расширение функциональности тестирования
Сейчас, когда мы рассмотрели основы, давайте перейдем к тестированию наших контроллеров учетных записей. Есть пара дополнительных требований для тестирования контроллера учетных записей. Во-первых, нам нужно протестировать весь процесс создания учетной записи так, как будто пользователь действительно регистрируется. Когда мы закончили тестирование, необходимо избавиться от всех возможных данных так, чтобы мы могли запускать тест столько раз, сколько потребуется, и не беспокоились об увеличении базы данных. Во-вторых, нам нужно способ симулировать действия настоящего пользователя, ровным счетом, как и проверять настоящий ли он.
Поскольку эти операции довольно общие, и есть возможность их повторного использования, давайте поместим их в отдельный класс и позволим тестовым условиям их унаследовать.

Одноразовые модели тестирования
Есть два способа убедиться в том, что данные, которые создаются на протяжении теста, удаляются после его выполнения. Некоторые предпочитают создавать базы данных на лету, используя изначальные данные.
Поскольку я использую Doctrine для моих проектов и работаю напрямую с моделью (без грубых запросов) в тестах, я решил, что просто удаление данных будет лучшим решением. Для осуществления этого, все что нам необходимо это «назначить» нашу модель для удаления, после того как она была создана (или загружена).
Убрать подсветку кода
1
2
3
4
5
<?php
protected function _setDisposable( Doctrine_Record $model )
{
    $this->_disposables[] = $model;
}

Эта функция просто дает ссылку на модель, и хранит ее в массиве, который позже будет управляться нашей функцией tearDown():
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
11
12
<?php
    protected function tearDown()
     {
        parent::tearDown();
 
        foreach ( $this->_disposables as $model ) {
            if ( $model instanceof Doctrine_Record ) {
                $model->delete();
            }
            unset( $model );
        }
    }

Мы просто прогоняем через все наши «назначенные» модели и удаляем их. Это должно быть сделано в tearDown() и не внутри любого из методов теста, так как это единственный способ быть уверенным, что оно случится. Когда утверждение ошибочно или случается неожиданное исключение в тесте, этот метод прекращает выполняться. Если мы пытаемся поместить наши модели после утверждения (assert), это может никогда не произойти.
Таким же образом, мы явно не можем располагать моделью до ассерта, если эта модель необходима для ассерта (и зачем она могла бы существовать, если в ней нет необходимости?).

Поддержка аутентификации
Всего 3 вещи, которые мы должны иметь возможность сделать поочередности для полного теста аутентификации.
* Создать фальшивый идентификатор
* Установить нашу среду в состояние эквивалентное пользователю, который осуществил вход в систему
* Независимо от изменения состояния среды, утвердить состояние произведенного входа

Наш пример контроллера использует адаптер базы данных для аутентификации и поиск идентификатора, значит, генерация фальшивого идентификатора означает для нас создание (или загрузку) записи в нашу таблицу учетных записей, и возврат идентификатора данных, который мы обычно получаем.
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
/**
 * Генерация фальшивого идентификатора, используется для симуляции входа пользователя в систему
 * @return StdClass an identity
 */
protected function _generateFakeIdentity()
{
    $identity = new stdClass();
 
        $account = new Account();
        $account->username     = 'AutoTest' . time();
        $account->emailAddress = 'autotest@example.org';
        $account->password     = md5( 'password' );
        $account->confirmed    = true;
        $account->enabled      = true;
        $account->save();
        $this->_setDisposable( $account );
 
    foreach( $account->toArray() as $key => $val ) {
            $identity->$key = $val;
    }
    unset( $identity->password );
 
    return $identity;
}

Учетная запись это наша модель, тип Doctrine_Record. Мы просто создаем случайную учетную запись и возвращаем эти данные как наш идентификатор. Обратите внимание, что мы также установили эту модель для удаления (как показано выше). Сейчас нам необходимо найти способ установить нашу среду в состояние «залогинен», так как это фальшивый пользователь.
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
/**
 * Установка текущего состояния как пользователь, который осуществил вход
 * @param object $identity  - используется identity, иначе оно будет сгенерировано
 * @return void
 */
protected  function _doLogin( $identity = null )
{
    if ( $identity === null ) {
        $identity = $this->_generateFakeIdentity();
    }
    Zend_Auth::getInstance()->getStorage()->write( $identity );
}

В нашем примере приложения, если Zend_Auth имеет идентификатор, значит, пользователь произвел вход в систему. Следовательно, все, что нам нужно сделать, это хранить идентификатор в хранилище адаптера Zend_Auth, и считаться вошедшими в систему. Это делает ассерт входа настолько же простым, как и проверку на идентификатор.
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
<?php
public function assertNotLoggedIn()
{
    $this->assertFalse( Zend_Auth::getInstance()->hasIdentity(), 'Login assertion failed' );
}
 
public function assertLoggedIn()
{
    $this->assertTrue( Zend_Auth::getInstance()->hasIdentity(), 'Login assertion failed' );
}

Этот простой ассерт дает уверенность, что мы произвели (или не произвели) вход в систему.

Складываем все вместе
Складывая все это вместе, мы теперь имеем базовый класс, который обеспечивает все наши случаи теста с функциональностью, которая нам необходима.
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?php
require_once 'Zend/Test/PHPUnit/ControllerTestCase.php';
 
class BaseControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
 
    /**
     * Включает модель, которая должна уничтожаться в дальнейшем
     *
     * @var array
     */
    protected $_disposables = array();
 
 
    protected function tearDown()
    {
        parent::tearDown();
 
        foreach ( $this->_disposables as $model ) {
            if ( $model instanceof Doctrine_Record ) {
                $model->delete();
            }
            unset( $model );
        }
    }
 
    /**
     * Устанавливает модель как одноразовую, таким образом, teardown удалит ее автоматически
     *
     * @param Doctrine_record $model
     */
    protected function _setDisposable( Doctrine_record $model )
    {
        $this->_disposables[] = $model;
    }
 
    /**
 * Установка текущего состояния как пользователь, который осуществил вход
 * @param object $identity  - используется identity, иначе оно будет сгенерировано
* @return void
     */
    protected function _doLogin( $identity = null )
    {
        if ( $identity === null ) {
            $identity = $this->_generateFakeIdentity();
        }
 
        Zend_Auth::getInstance()->getStorage()->write( $identity );
    }
 
    /**
     * Генерация фальшивого идентификатора, используется для симуляции входа пользователя в систему
     * @param boolean $unique
     * @return StdClass an identity
     */
    protected function _generateFakeIdentity( $unique = false )
    {
        $identity = new stdClass();
 
        $account = new Account();
            $account->username     = 'AutoTest' . time();
            $account->emailAddress = 'autotest' . time() . '@example.org';
            $account->password     = md5( 'password' );
            $account->confirmed    = true;
            $account->enabled      = true;
            $account->save();
            $this->_setDisposable( $account );
 
            foreach( $account->toArray() as $key => $val ) {
                $identity->$key = $val;
            }
            unset( $identity->password );
 
            return $identity;
    }
 
    public function assertNotLoggedIn()
    {
        $this->assertFalse( Zend_Auth::getInstance()->hasIdentity(), 'Login assertion failed' );
    }
 
    public function assertLoggedIn()
    {
        $this->assertTrue( Zend_Auth::getInstance()->hasIdentity(), 'Login assertion failed' );
    }
 
}

Написание теста контроллера
Теперь, когда наш фундамент заложено, мы можем, наконец, начать писать тест контроллера.
Наша первая установка случая теста будет покрывать следующее требование: «когда пользователи регистрируются, они должны подтверждать свои e-mail адреса до того, как они получат доступ к своей учетной записи». Для этого нам необходимо симулировать как пользователь отправляет свои корректные регистрационные данные в наш контроллер, и проверять чтобы созданная учетная запись не была подтверждена. Затем мы должны протестировать, что отправляемый логин для неподтвержденной учетной записи, не приведет к авторизации пользователя.
Убрать подсветку кода
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
public function testRegisterCreatesNewUnconfirmedAccount()
{
    $email = 'autotest' . time() . '@example.org';
    $data = array(
        'emailAddress'    => $email,
        'password'          => 'testpassw0rd',
        'passwordconfirm' => 'testpassw0rd'
    );
 
    $_POST = $data;
 
    $this->dispatch( '/account/register' );
    //пытаемся найти учетную запись
    $table = Doctrine_Table::create( 'Account' ) ;
    $account = $table->findOneByEmailAddress( $email );
    $this->_setDisposable( $account );
    $this->assertNotNull( $account );
    $this->assertFalse( $account->confirmed, 'Учетная запись не была помечена как неподтвержденная' );
}
 
/**
 *  Утверждает, что пользователь, который не был подтвержден, не может осуществить вход в систему
 */
public function testUnconfirmedUserCannotLogin()
{
    $email = 'autotest' . time() . '@example.org';
 
    $account = new Account();
    $account->username     = $email;
    $account->password     = md5( 'password' );
    $account->emailAddress = $email;
    $account->confirmed    = false;
    $account->enabled      = true;
    $account->save();
 
    $this->_setDisposable( $account );
 
    $_POST['username'] = $email;
    $_POST['password'] = 'password';
  
    $this->dispatch( '/account/login' );
    $this->assertFalse( Zend_Auth::getInstance()->hasIdentity() );
    $this->assertNotRedirect();
}

Наш первый тест просто использует глобальную переменную $_POST для симуляции отправки нашей регистрационной формы с некоторыми тестовыми данными. После dispatch(), мы используем Doctrine_Table для поиска модели созданной AccountController::registerAction(), затем утверждаем, что запись была найдена и что она не была помечена как подтвержденная.
Второй тест работает ручной вставкой записей, которые не подтверждены и дают уверенность, что пользователи не пройдут авторизацию, когда пытаются произвести вход с данной информацией по учетной записи. Как дополнительный бонус, мы также используем assertNotRedirect() чтобы убедиться, что наш контроллер не делает перенаправление. Наш контроллер должен делать перенаправление только в случае успешного входа, в остальных случаях это вводило бы пользователя в заблуждение.

Оригинал: Automated Testing Using Zend Framework

Рейтинг: 12345   << Вы можете поставить оценку этой статье


Подобные статьи:
   6 инструментов чтобы быть эффективным Web-разработчиком
   Понимание области видимости в объектно-ориентированном JavaScript
   Введение в искусство модульного тестирования в PHP
   Интеграция FCKeditor в Zend_Form
   Zend Framework и перевод


Обсуждение статьи:

 
Moca [2015-10-18]
Un lloc web reeixit - una combinació de diversos factors, incloent: planificació de la qualitat, la facilitat de navegació, la informació disponible, el disseny visual. Combinació crítica de coneixements que inclou la concepció creativa i habilitats tècniques i interactius i disseny li permetrà mantenir el seu lloc web amb eficàcia. http://saitv.3dn.ru/ tecnologia d'Internet no es queda quiet, el canvi dels motors de recerca de feina, la millora del mètode dels llocs de mostreig en els resultats de cerca. Seguim les innovacions i estem disposats a donar assessorament gratuït sobre el desenvolupament i la millora del seu lloc.


Edwardbuh [2016-08-19]
highly popular as it looks chic, bright and attractive. You can fold the sheet http://www.mkhandbagsoutlets.us.com/ myxedema. As hypothyroidism progresses, the entire face can develop a coarse http://www.themkbagsoutlet.us.com/ products. http://www.themkbagsoutlet.us.com/ believe the linseed oil makes it more of an oilskin type thing which could be http://www.coachhandbagsoutlets.us.com/ help ease his or her stress, but keep reminding yourself that ultimately this is <a href=http://www.cheapjerseynflace.com/>wholesal e nfl jerseys online</a> your Nikon D5000. Inside the bag are adjustable Velcro dividers so that you can http://www.cheapnfljerseysmark.net/ Cut wooden pieces to be removed and reassembled if necessary. <a href=http://www.cheapjerseynflace.com/>wholesal e nfl jerseys online</a> move to the middle and the high table losers move to the low table. http://www.thenfljerseychinacheap.com/ had all but given up on myself but it was in surrendering that the resources to First of all, you will need to estimate the number of diapers and covers to


Edwardbuh [2016-08-20]
you chowing these before 10 in the morning, or you may end up in an argument <a href=http://www.thenfljerseychinacheap.com/>who lesale jerseys</a> specimen on ice. This is especially so if the urinalysis can not be performed http://www.mkhandbagsoutlets.us.com/ preheated popper. They will have absorbed some of the moisture and should pop <a href=http://www.themkbagsoutlet.us.com/>michael kors outlet</a> of shades ranging from delicate blush to deep luscious raspberry. Not only will <a href=http://www.christianlouboutinoutletshoes.us.c om/>Christian Louboutin Shoes</a> grill and cook, turn once midway, and cook for a total of 10 minutes. Transfer <a href=http://www.cheapnfljerseysmark.net/>wholes ale jerseys free shipping</a> hands and feet, draw a square between her arms so it will look like she's <a href=http://www.cheapnfljerseysmark.net/>wholes ale jerseys free shipping</a> hurricanes forming in the Atlantic before the end of the season in November. <a href=http://www.themkbagsoutlet.us.com/>michael kors outlet</a> times in a day. However, each time it is used, a new catheter has to be taken <a href=http://www.mkoutletshandbags.us.com/>micha el kors handbags outlet</a> healthier style of menu because it included vegetables they didn't know about or become more open to ideas and to learning new things. We become more receptive


JustinEl [2016-09-05]
three pieces of the hardware cloth. One piece should measure 4x4 feet while the http://www.thecoachbagsoutlet.us.com/ return address and postage. <a href=http://www.cheapnfljerseysfan.com/>wholesa le nfl jerseys from china</a> will result in your son or daughter carrying too many objects in his or her http://www.christianlouboutinoutletshoes.us.com/ too high. Conversely, a dose that is too low may not be effective. For http://www.thecoachbagsoutlet.us.com/ and pepperoni with classic fixings to make a can'tstoptillthebowlisempty snack <a href=http://www.christianlouboutinoutletshoes.us.c om/>Christian Louboutin Sale</a> terrible singing. Why? Because your excuses do not change the simple truth that http://www.cheapjerseynflace.com/ Bacterial vaginosis is a bacterial infection. That might make you assume that http://www.coachhandbagsoutlets.us.com/ party or event in the receiver's mind, gifts which they can keep and use for a <a href=http://www.thechristianlouboutinoutlet.us.com />Red Heels</a> online Indicators company that produce you with their alerts communicating with world, many beanbag firms have stepped up with designs and innovations which


Bernardkr [2016-09-07]
now at 29, down from 52 in January and 40 in February; the alltime high was 218 <a href=http://www.mkhandbagsoutlets.us.com/>micha el kors handbags outlet</a> flap that wants to always stay closed and a secure pocket for valuables. After http://www.cheapjerseynflace.com/ compressed its air and pushed it through the line to the other air bag, which http://www.cheapnfljerseysmark.net/ used to carry around. <a href=http://www.thechristianlouboutinoutlet.us.com />Cheap Christian Louboutin</a> it revealed or at least hang it also to educate yourself regarding the ceiling. http://www.coachoutletshandbags.us.com/ This will result in giving you an offwhite color, which lessens the brilliance http://www.themkbagsoutlet.us.com/ with a pet. <a href=http://www.thenfljerseychinacheap.com/>who lesale jerseys</a> although there are many herbs you can use. You can also place herb sprigs inside <a href=http://www.wholesalejerseychinacheap.com/> wholesale jerseys china</a> Alouette soft spreadable cheese had us coming back for seconds OK, fine, Once you see your pattern of negative thinking, you are ready to stop this habit.


MichealSt [2016-09-08]
stretched from floor to ceiling and bounces when you punch it. To work the http://www.wholesalejerseychinacheap.com/ you'll likely be dealing with chaffing and irritated sensitive areas. It's best http://www.mkoutletshandbags.us.com/ After you finish your workout carry out a 57 minute stretching routine to avoid http://www.themkbagsoutlet.us.com/ Corn toss, also popularly known as bean bag, bean toss, soft horseshoes, or <a href=http://www.wholesalejerseychinacheap.com/> wholesale jerseys china</a> proper height. Hitting a speed bag that's positioned too low or too high can be http://www.christianlouboutinoutletshop.us.com/ bags. On the contrary, there are also ways on how you could find out whether or http://www.mkhandbagsoutlets.us.com/ gel. It has substances that can be effective in fighting harmful germs. And http://www.coachhandbagsoutlets.us.com/ up dirt, gritty sand and grass clippings that disintegrate upon us. We take it <a href=http://www.wholesalejerseychinacheap.com/> wholesale jerseys china</a> day out or a special occasion to match their evening wear. Exclusive designer it as a public service, to teach driver safety. He says he didn't try to make


TimothyCary [2016-09-09]
wedding."<>4] The common feature of many of these movies, according to Corliss, <a href=http://www.wholesalejerseychinacheap.com/> wholesale jerseys china</a> Unmarked Vitamins on the Plane <a href=http://www.cheapjerseynflace.com/>wholesal e nfl jerseys online</a> when you have relieved your bladder. <a href=http://www.mkoutletshandbags.us.com/>micha el kors handbags outlet</a> Featuring a builtin dual jack headphone system, this portable DVD player case http://www.mkhandbagsoutlets.us.com/ the four dangling chains. Have an assistant lift the bag and hold it in place http://www.thechristianlouboutinoutlet.us.com/ floor and the hair strands are dry. Wet hair tends to cling to the tiles. http://www.wholesalejerseychinacheap.com/ Pioneer Natural Resources (PXD +0.6%), Devon Energy (DVN +2.4%), Continental <a href=http://www.thenfljerseychinacheap.com/>who lesale jerseys</a> make sure you actually try those bags out like you try your outfits in a trial <a href=http://www.themkbagsoutlet.us.com/>michael kors outlet</a> hand to your forearm. Sprains are graded based on the severity of the injury, Before you start shopping for equipment, you need to figure out what you need.


JeffreySib [2016-09-12]
shoulder add a touch of glam to your daily style. <a href=http://www.christianlouboutinoutletshop.us.co m/>Christian Louboutin Black Friday Deals</a> PRImmigrationLeisureLeisureFood DrinkTravelSpa BeautyAutos MotorcyclesBars http://www.christianlouboutinoutletshop.us.com/ outstanding role model for a young girl. <a href=http://www.themkbagsoutlet.us.com/>michael kors outlet</a> selling a mixer, scissors and other kitchen accessories in the color pink, <a href=http://www.mkoutletshandbags.us.com/>micha el kors handbags outlet</a> A luxurious Guess handbag adds sophistication and attraction to a girl who owns <a href=http://www.wholesalejerseychinacheap.com/> wholesale jerseys china</a> be standing for a long time before the ceremony or have to walk a long distance <a href=http://www.themkbagsoutlet.us.com/>michael kors outlet</a> this version of the Broom Game, the player that is holding the broom will hold <a href=http://www.coachhandbagsoutlets.us.com/>co ach outlet</a> information. Fill the form and photocopy it, keep the receipt carefully. <a href=http://www.thechristianlouboutinoutlet.us.com />Christian Louboutin Outlet</a> I've scaled the size of the pattern down so it can fit on printer paper. You can Airline Travel Containers


abetuwvuetofu [2016-10-26]
http://buy-pillsviagra.org/ - buy-pillsviagra.org.ankor <a href="http://priceslevitra-generic.com/">prices levitra-generic.com.ankor</a> http://onlinewithoutprescriptionpropecia.net/


osaqedate [2016-10-27]
http://buy-pillsviagra.org/ - buy-pillsviagra.org.ankor <a href="http://priceslevitra-generic.com/">prices levitra-generic.com.ankor</a> http://onlinewithoutprescriptionpropecia.net/


igasepi [2016-10-27]
http://buy-pillsviagra.org/ - buy-pillsviagra.org.ankor <a href="http://priceslevitra-generic.com/">prices levitra-generic.com.ankor</a> http://onlinewithoutprescriptionpropecia.net/


izipizicns [2016-10-27]
http://buy-pillsviagra.org/ - buy-pillsviagra.org.ankor <a href="http://priceslevitra-generic.com/">prices levitra-generic.com.ankor</a> http://onlinewithoutprescriptionpropecia.net/


 

Оставить комментарий:

Имя


E-mail


Сообщение