--- layout: doc title: Advanced Usage - Codeception Docs ---
💡 You are reading docs for latest Codeception 5. Read for 4.x
# Advanced Usage In this chapter, we will cover some techniques and options that you can use to improve your testing experience and keep your project better organized. ## Cest Classes Cest is a common test format for Codeception, it is "Test" with the first C letter in it. It is scenario-driven format so all tests written in it are executed step by step. Unless you need direct access to application code inside a test, Cest format is recommended. As it provides more readable code for functional, api, and acceptance tests. A new Cest class can be created via `g:cest` command: ``` php vendor/bin/codecept generate:cest suitename CestName ``` The generated file will look like this: ```php amOnPage('/'); $I->click('Login'); $I->fillField('username', 'john'); $I->fillField('password', 'coltrane'); $I->click('Enter'); $I->see('Hello, John'); $I->seeInCurrentUrl('/account'); } } ``` As you see, Cest classes have no parents. This is done intentionally. It allows you to extend your classes with common behaviors and workarounds that may be used in child classes. But don't forget to make these methods `protected` so they won't be executed as tests. Cest format also can contain hooks based on test results: * `_failed` will be executed for failed test * `_passed` will be executed for passed test ```php public function _failed(AcceptanceTester $I) { // will be executed on test failure } public function _passed(AcceptanceTester $I) { // will be executed when test is successful } ``` ## Skip Tests To mark test as skipped `Skip` attribute can be used: ```php shouldNotBeExecuted) { // skip test on condition // please note that `_before` is still executed for this test // and browser is launched in case of acceptance test $scenario->skip('This test is skipped on this condition'); } // test body } ``` Unit tests can be skipped via the attribute or by using `markTestSkipped` method: ```php shouldNotBeExecuted) { $this->markTestSkipped(); } } } ``` ## Incomplete Tests Tests can be marked as Incomplete, in this case, they also will be skipped. To mark a test as incomplete use `Codeception\Attribute\Incomplete` which should be used similarly to `Skip` attribute: ```php use Codeception\Attribute\Incomplete; // --- #[Incomplete] public function testNotReadyYet() { } #[Incomplete('I will implement it tomorrow, I promise')] public function testNotReadyToday() { } ``` ## Groups There are several ways to execute a bunch of tests. You can run tests from a specific directory: ``` php vendor/bin/codecept run tests/acceptance/admin ``` You can execute one (or several) specific groups of tests: ``` php vendor/bin/codecept run -g admin -g editor ``` The concept of groups was taken from PHPUnit and behaves in the same way. For Test and Cest files you can use the `Group` attribute to add a test to a group. ```php sendGet($example[0]); $I->seeResponseCodeIs($example[1]); } } ``` ## Example Annotation As well as the `\Codeception\Attribute\Examples` attribute, available for Cest tests, the `@example` attribute allows you to inject test parameters in place of an actual [DataProvider](#dataprovider-attribute) for Unit tests. ```php assertNotEmpty($value, "Expected a value"); } } ``` > `@testWith`: as of [Codeception 5.0](https://github.com/Codeception/Codeception/pull/6491), PHPUnit's `@testWith` is no longer supported. `@example` is a good, almost drop-in, replacement. ## DataProvider Attribute You can also use the `@dataProvider` annotation for creating dynamic examples for [Cest classes](#Cest-Classes), using a **protected method** for providing example data: ```php amOnPage($example['url']); $I->see($example['title'], 'h1'); $I->seeInTitle($example['title']); } protected function pageProvider() : array // to make it public use `_` prefix { return [ ['url'=>"/", 'title'=>"Welcome"], ['url'=>"/info", 'title'=>"Info"], ['url'=>"/about", 'title'=>"About Us"], ['url'=>"/contact", 'title'=>"Contact Us"] ]; } } ``` ## Before/After Attributes You can control execution flow with `@before` and `@after` annotations. You may move common actions into protected (non-test) methods and invoke them before or after the test method by putting them into annotations. It is possible to invoke several methods by using more than one `@before` or `@after` annotation. Methods are invoked in order from top to bottom. ```php amOnPage('/login'); $I->fillField('Username', 'miles'); $I->fillField('Password', 'davis'); $I->click('Login'); } #[Before('login')] public function banUser(AcceptanceTester $I) { $I->amOnPage('/users/charlie-parker'); $I->see('Ban', '.button'); $I->click('Ban'); } // you can specify multiple before and after methods: #[Before('login', 'cleanup')] #[After('logout', 'close')] public function addUser(AcceptanceTester $I) { $I->amOnPage('/users/charlie-parker'); $I->see('Ban', '.button'); $I->click('Ban'); } } ``` ### Dependencies With the `Depends` attribute, you can specify a test that should be passed before the current one. If that test fails, the current test will be skipped. You should pass the method name of the test you are relying on. ```php current()` method. ```php // retrieve current environment $scenario->current('env'); // list of all enabled modules $scenario->current('modules'); // test name $scenario->current('name'); // browser name (if WebDriver module enabled) $scenario->current('browser'); // capabilities (if WebDriver module enabled) $scenario->current('capabilities'); ``` You can inject `\Codeception\Scenario` like this: ```php public function myTest(\Codeception\Scenario $scenario) { // list all metadata variables codecept_debug($scenario->current()); // do some actions according to conditions if ($scenario->current('browser') == 'chrome') { // ... } } ``` `Codeception\Scenario` is also available in Actor classes and StepObjects. You can access it with `$this->getScenario()`. ## Shuffle By default, Codeception runs tests in alphabetic order. To ensure that tests are not depending on each other (unless explicitly declared via `@depends`) you can enable `shuffle` option. ```yaml # inside codeception.yml settings: shuffle: true ``` Alternatively, you may run tests in the shuffle without changing the config: ```yaml codecept run -o "settings: shuffle: true" ``` Tests will be randomly reordered on each run. When tests are executed in shuffle mode a seed value will be printed. Copy this seed value from the output to be able to rerun tests in the same order. ```yaml $ codecept run Codeception PHP Testing Framework v2.4.5 Powered by PHPUnit 5.7.27 by Sebastian Bergmann and contributors. [Seed] 1872290562 ``` Pass the copied seed into `--seed` option: ```yaml codecept run --seed 1872290562 ``` ## Dependency Injection Codeception supports simple dependency injection for `Cest` and `Codeception\Test\Unit` classes. It means that you can specify which classes you need as parameters of the special `_inject()` method, and Codeception will automatically create the respective objects and invoke this method, passing all dependencies as arguments. This may be useful when working with Helpers. Here's an example for Cest: ```php signUp = $signUp; $this->navBar = $navBar; } public function signUp(AcceptanceTester $I) { $this->navBar->click('Sign up'); $this->signUp->register([ 'first_name' => 'Joe', 'last_name' => 'Jones', 'email' => 'joe@jones.com', 'password' => '1234', 'password_confirmation' => '1234' ]); } } ``` And for Test classes: ```php math = $math; } public function testAll() { $this->assertEquals(3, $this->math->add(1, 2)); $this->assertEquals(1, $this->math->subtract(3, 2)); } } ``` However, Dependency Injection is not limited to this. It allows you to **inject any class**, which can be constructed with arguments known to Codeception. In order to make auto-wiring work, you will need to implement the `_inject()` method with the list of desired arguments. It is important to specify the type of arguments, so Codeception can guess which objects are expected to be received. The `_inject()` will only be invoked once, just after the creation of the TestCase object (either Cest or Test). Dependency Injection will also work in a similar manner for Helper and Actor classes. Each test of a Cest class can declare its own dependencies and receive them from method arguments: ```php createDummyUser(); $userPage->login($user->getName(), $user->getPassword()); $userPage->updateProfile(['name' => 'Bill']); $I->see('Profile was saved'); $I->see('Profile of Bill','h1'); } } ``` Moreover, Codeception can resolve dependencies recursively (when `A` depends on `B`, and `B` depends on `C` etc.) and handle parameters of primitive types with default values (like `$param = 'default'`). Of course, you are not allowed to have *cyclic dependencies*.
Improve this guide