2e86c939
xu
“首次提交”
|
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
|
# Working with Data
Tests should not affect each other. That's a rule of thumb. When tests interact with a database,
they may change the data inside it, which would eventually lead to data inconsistency.
A test may try to insert a record that has already been inserted, or retrieve a deleted record.
To avoid test failures, the database should be brought back to its initial state before each test.
Codeception has different methods and approaches to get your data cleaned.
This chapter summarizes all of the notices on clean-ups from the previous chapters
and suggests the best strategies of how to choose data storage backends.
When we decide to clean up a database, we should make this cleaning as fast as possible. Tests should always run fast.
Rebuilding the database from scratch is not the best way, but might be the only one. In any case,
you should use a special test database for testing. **Do not ever run tests on development or production databases!**
## Db
Codeception has a `Db` module, which takes on most of the tasks of database interaction.
```yaml
modules:
config:
Db:
dsn: 'PDO DSN HERE'
user: 'root'
password:
```
<div class="alert alert-notice">
Use <a href="http://codeception.com/docs/06-ModulesAndHelpers#Dynamic-Configuration-With-Params">module parameters</a>
to set the database credentials from environment variables or from application configuration files.
</div>
Db module can cleanup database between tests by loading a database dump. This can be done by parsing SQL file and
executing its commands using current connection
```yaml
modules:
config:
Db:
dsn: 'PDO DSN HERE'
user: 'root'
password:
dump: tests/_data/your-dump-name.sql
cleanup: true # reload dump between tests
populate: true # load dump before all tests
```
Alternatively an external tool (like mysql client, or pg_restore) can be used. This approach is faster and won't produce parsing errors while loading a dump.
Use `populator` config option to specify the command. For MySQL it can look like this:
```yaml
modules:
enabled:
- Db:
dsn: 'mysql:host=localhost;dbname=testdb'
user: 'root'
password: ''
cleanup: true # run populator before each test
populate: true # run populator before all test
populator: 'mysql -u $user $dbname < tests/_data/dump.sql'
```
See the []Db module reference](http://codeception.com/docs/modules/Db#SQL-data-dump) for more examples.
To ensure database dump is loaded before all tests add `populate: true`. To clean current database and reload dump between tests use `cleanup: true`.
<div class="alert alert-notice">
A full database clean-up can be painfully slow if you use large database dumps. It is recommended to do more data testing
on the functional and integration levels, this way you can get performance bonuses from using ORM.
</div>
In acceptance tests, your tests are interacting with the application through a web server. This means that the test
and the application work with the same database. You should provide the same credentials in the Db module
that your application uses, then you can access the database for assertions (`seeInDatabase` actions)
and to perform automatic clean-ups.
The Db module provides actions to create and verify data inside a database.
If you want to create a special database record for one test,
you can use [`haveInDatabase`](http://codeception.com/docs/modules/Db#haveInDatabase) method of `Db` module:
```php
<?php
$I->haveInDatabase('posts', [
'title' => 'Top 10 Testing Frameworks',
'body' => '1. Codeception'
]);
$I->amOnPage('/posts');
$I->see('Top 10 Testing Frameworks');
```
`haveInDatabase` inserts a row with the provided values into the database.
All added records will be deleted at the end of the test.
If you want to check that a table record was created
use [`seeInDatabase`](http://codeception.com/docs/modules/Db#haveInDatabase) method:
```php
<?php
$I->amOnPage('/posts/1');
$I->fillField('comment', 'This is nice!');
$I->click('Submit');
$I->seeInDatabase('comments', ['body' => 'This is nice!']);
```
See the module [reference](http://codeception.com/docs/modules/Db) for other methods you can use for database testing.
There are also modules for [MongoDb](http://codeception.com/docs/modules/MongoDb),
[Redis](http://codeception.com/docs/modules/Redis),
and [Memcache](http://codeception.com/docs/modules/Memcache) which behave in a similar manner.
### Sequence
If the database clean-up takes too long, you can follow a different strategy: create new data for each test.
This way, the only problem you might face is duplication of data records.
[Sequence](http://codeception.com/docs/modules/Sequence) was created to solve this.
It provides the `sq()` function which generates unique suffixes for creating data in tests.
## ORM modules
Your application is most likely using object-relational mapping (ORM) to work with the database. In this case,
Codeception allows you to use the ORM methods to work with the database, instead of accessing the database directly.
This way you can work with models and entities of a domain, and not on tables and rows.
By using ORM in functional and integration tests, you can also improve performance of your tests.
Instead of cleaning up the database after each test, the ORM module will wrap all the database actions into transactions
and roll it back at the end. This way, no actual data will be written to the database.
This clean-up strategy is enabled by default,
you can disable it by setting `cleanup: false` in the configuration of any ORM module.
### ActiveRecord
Popular frameworks like Laravel, Yii, and Phalcon include an ActiveRecord data layer by default.
Because of this tight integration, you just need to enable the framework module, and use its configuration for database access.
Corresponding framework modules provide similar methods for ORM access:
* `haveRecord`
* `seeRecord`
* `dontSeeRecord`
* `grabRecord`
They allow you to create and check data by model name and field names in the model. Here is the example in Laravel:
```php
<?php
// create record and get its id
$id = $I->haveRecord('posts', ['body' => 'My first blogpost', 'user_id' => 1]);
$I->amOnPage('/posts/'.$id);
$I->see('My first blogpost', 'article');
// check record exists
$I->seeRecord('posts', ['id' => $id]);
$I->click('Delete');
// record was deleted
$I->dontSeeRecord('posts', ['id' => $id]);
```
<div class="alert alert-notice">
Laravel5 module also provides `haveModel`, `makeModel` methods which use factories to generate models with fake data.
</div>
If you want to use ORM for integration testing only, you should enable the framework module with only the `ORM` part enabled:
```yaml
modules:
enabled:
- Laravel5:
- part: ORM
```
```yaml
modules:
enabled:
- Yii2:
- part: ORM
```
This way no web actions will be added to `$I` object.
If you want to use ORM to work with data inside acceptance tests, you should also include only the ORM part of a module.
Please note that inside acceptance tests, web applications work inside a webserver, so any test data can't be cleaned up
by rolling back transactions. You will need to disable cleaning up,
and use the `Db` module to clean the database up between tests. Here is a sample config:
```yaml
modules:
enabled:
- WebDriver:
url: http://localhost
browser: firefox
- Laravel5:
cleanup: false
- Db
```
### DataMapper
Doctrine is also a popular ORM, unlike some others it implements the DataMapper pattern and is not bound to any framework.
The [Doctrine2](http://codeception.com/docs/modules/Doctrine2) module requires an `EntityManager` instance to work with.
It can be obtained from a Symfony framework or Zend Framework (configured with Doctrine):
```yaml
modules:
enabled:
- Symfony
- Doctrine2:
depends: Symfony
```
```yaml
modules:
enabled:
- ZF2
- Doctrine2:
depends: ZF2
```
If no framework is used with Doctrine you should provide the `connection_callback` option
with a valid callback to a function which returns an `EntityManager` instance.
Doctrine2 also provides methods to create and check data:
* `haveInRepository`
* `grabFromRepository`
* `grabEntitiesFromRepository`
* `seeInRepository`
* `dontSeeInRepository`
### DataFactory
Preparing data for testing is a very creative, although boring, task. If you create a record,
you need to fill in all the fields of the model. It is much easier to use [Faker](https://github.com/fzaninotto/Faker)
for this task, which is more effective to set up data generation rules for models.
Such a set of rules is called *factories*
and are provided by the [DataFactory](http://codeception.com/docs/modules/DataFactory) module.
Once configured, it can create records with ease:
```php
<?php
// creates a new user
$user_id = $I->have('App\Model\User');
// creates 3 posts
$I->haveMultiple('App\Model\Post', 3);
```
Created records will be deleted at the end of a test.
The DataFactory module only works with ORM, so it requires one of the ORM modules to be enabled:
```yaml
modules:
enabled:
- Yii2:
configFile: path/to/config.php
- DataFactory:
depends: Yii2
```
```yaml
modules:
enabled:
- Symfony
- Doctrine2:
depends: Symfony
- DataFactory:
depends: Doctrine2
```
DataFactory provides a powerful solution for managing data in integration/functional/acceptance tests.
Read the [full reference](http://codeception.com/docs/modules/DataFactory) to learn how to set this module up.
## Conclusion
Codeception also assists the developer when dealing with data. Tools for database population
and cleaning up are bundled within the `Db` module. If you use ORM, you can use one of the provided framework modules
to operate with database through a data abstraction layer, and use the DataFactory module to generate new records with ease.
|