Codeception Actor Actor vs Helper?

Viewed 866

In Codeception, the documentation suggests I add actions to Helper\Acceptance class which are then included in the AcceptanceTester class. The AcceptanceTester class also says this:

class AcceptanceTester extends \Codeception\Actor
{
    use _generated\AcceptanceTesterActions;

   /**
    * Define custom actions here
    */
}

So I can add my actions to the AcceptanceTester which is more straightforward for both a developer and his IDE than the auto-generated trait.

Is there any difference and why the documentation suggests the less straightforward way?

2 Answers

I Just checked the documentation. So Helper\Acceptance class is act as codeception module. Because it's a module, defining some public methods to this class can be loaded/called in another module. See example here. That's the difference with AcceptanceTester class, the methods will only accessible via $I instance. Honestly never try all of the implementation deeper. But this is a very good topic to discuss.

Here is my take on this. Documentation is a bit finicky so I had to put this together from multiple pages (references are included below).

Actors

All actions and assertions are performed by the Actor object source

Actor is actually used when you define your tests:

public function loginAsRegularUser(\AcceptanceTester $I)

or

$I = new AcceptanceTester($scenario);

Actor itself acts as a proxy for the modules (helpers):

The FunctionalTester class has its methods defined in modules. Actually, it doesn’t contain any of them, but rather acts as a proxy. It knows which module executes this action and passes parameters into it. source

To take advantage of IDE autocompletion, you may need to manually generate methods:

To make your IDE see all of the FunctionalTester methods, you should run the codecept build command. It generates method signatures from enabled modules and saves them into a trait which is included in an actor. source

Remember, that there can be only 1 actor per suite (reference).

Helpers

Modules contain the actual actions and assertions:

All actions and assertions that can be performed by the Tester object in a class are defined in modules. source

You can extend the testing suite with your own actions and assertions, by writing them into a custom module, called a Helper. source

Conclusion

If you will further inspect \Codeception\Module and \Codeception\Actor you will realize that both serve very different purposes. Modules (or helpers) are meant to provide actions and assertions.

On the other hand, actor is a proxy between module and the tested code. Actor has access to $scenario where you can get meta information such as test description or its name.

Modules are able to interact with other modules (source) and they have lifecycle hooks (source).

Bonus - StepObjects

StepObjects are great if you need some common functionality for a group of tests. (source)

StepObjects are extended from actors as they extend the actor of a given suite. Now it probably makes more sense why StepObjects are assigned to a specific suite instead of being a generic class:

php vendor/bin/codecept generate:stepobject acceptance Admin

When to use StepObjects? When you want to group actor-related actions such as grouping together multiple asserts or multiple actions.

Bonus - PageObjects

The PageObject pattern represents a web page as a class and the DOM elements on that page as its properties, and some basic interactions as its methods. (source)

Selenium documentation contains further details - link.

If you are familiar with MVC, PageObject looks like a model of a tested page i.e. it contains actual css and xpath queries so that they don't pollute actual tests. Refer to Codeception manual for an actual example.

Bonus Conclusion

So when to use StepObjects as opposed to PageObjects? Here is the recommendation from Codeception:

Group common [actor] actions together and move them to an Actor class or StepObjects. (source)

Move CSS and XPath locators into PageObjects. (source)

To paraphrase this, your css and xpath queries should be moved to PageObjects while common actions and assertions should be moved to StepObject.

Related