Cannot use Step Object in Cest Codeception - codeception

Following this tutorial https://codeception.com/docs/06-ReusingTestCode#StepObjects, but something simple is probably missing..
I have a StepObject class here:
tests/_support/Step/Acceptance/Admin.php
<?php
namespace Step\Acceptance;
class Admin extends \AcceptanceTester
{
public function loginAsAdmin()
{
$I = $this;
}
}
I documentation it says:
StepObject can be instantiated automatically when used inside the Cest format:
And gives this example
class UserCest
{
function showUserProfile(\Step\Acceptance\Admin $I)
{
$I->loginAsAdmin();
}
}
But how do I use this showUserProfile method inside the Cest file, for example inside the _before section?
I tried $this->showUserProfile(); but it says [ArgumentCountError] Too few arguments to function . It's not accepting the $I object. What should I pass to it and how?
Should I be requiring/referencing something somewhere?
And how can I use this class inside helper modules?

It looks like that you want to use the Helper functionality in Codeception.
Just find the correct helper class. The default one is tests/_support/Helper/Acceptance.php and add your method there...
<?php
namespace Helper;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
use Codeception\Module;
class Acceptance extends Module
{
public function loginAsAdmin()
{
// ... your login here
}
}
Make sure that the helper is activated in your codeception.yml and also be aware of to run the codecept build command to regenerate the auto-generated AcceptanceTester class. If you need the AcceptanceTester class to do assertions, you can add it as one function parameter.
If anything works as expected, you can just use your AcceptanceTester in your Cest without any extra dependency injection:
class UserCest
{
function showUserProfile(AcceptanceTester $I)
{
$I->loginAsAdmin();
}
}

Turns out the method is showUserProfile method which executes the StepObject method is executed automatically when the test is ran, as per:
Each public method of Cest (except those starting with _) will be executed as a test
So it looks like the StepObject is not designed to be called at will, it just runs when the test is executed.
If someone has a better answer I'll gladly accept it.

Related

Why Codeception creates new \Test instance for each test* method?

As a base I use \Codeception\TestCase\Test class.
And I noticed that for every test* methods defined in class, codeception recreates TestCase\Test class !
But Why?
As result I can't use class fields!
public function getName() {
if (!empty($this->_name)) {
return $this->_name;
} else $this->_name = uniqid('_name');
}
getName() for every test method will return new generated name.. thats wrong behavior as for me. It's possible to resolve this situation if I wants to use class fields for every test methods, like in normal OOP?

How to hook into beforeSuite event with Codeception for API Acceptance tests?

I am building API Acceptance tests with Codeception.
I am familiar with Unit tests there and I used the setUp method in those classes for all logic required before running all the tests of the class.
However I didn't find anything like this for Acceptance Tests.
Notice that I am using the "Class" approach, not the procedural way.
So I have a class like this...
class ResourceCest {
public function _beforeSuite(ApiTester $I)
{
// Ideally this would work, but it doesn't.
}
public function _before(ApiTester $I)
{
$I->am('Api Tester');
}
public function somethingThatIWantToExecute(ApiTester $I)
{
$I->sendGet('something');
// etc
}
}
I can make a method like setUp, but then Codeception executes it as a test and thus outputting something when running the tests.
You shouldn't define the _beforeSuite inside your Cest classes. Instead, you should use the Helper class inside _support.
Assuming you have a suite called api, you should have a ApiHelper.php class inside _support. There, you can define your methods, for instance:
<?php
namespace Codeception\Module;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class ApiHelper extends \Codeception\Module
{
public function _beforeSuite($I) {
var_dump($I);
die();
}
}
This should do the trick.

How to define constructor ?Where?

How to define constructor in Yii application?
Where ?to define the constructors?
I need to create constructors. Where it defines inside model or controller.
Can you guys give some example of formats ?
In a lot of Yii classes there are 2 methods that can be used to define initialization code : __construct() and init():
__construct() is a native php method to instantiate the object.
init() is called when Yii has performed it's own instantiation of the class (for example in a CActiveRecord class Yii has set the scenario name)
it's up to you to use
public function __construct()
{
//Your code
return parent::contruct()
}
or just to use the init method
public function init()
{
//Your code
}
if you use construct be carefull because some classes constructors have some params that you'll also have to set (for example CActiveRecord take the scenario name as a param)
If I were you I'll use the init method as often as possible.

Base class for common YII functions?

I know how to create a class the will allow me to instantiate it and use across my project. What I want to be able to do is have functions without instantiating classes. For example, I know how to do this:
$core = new core();
$val = $core->convertToMyNotation($anotherval);
But what I want is to be able to do this ANYWHERE in any view, class whatever:
$val = convertToMyNotation($anotherval);
Where would I place these functions in order to be able to do that?
best way to do it, create a public function in components/Controller.php
public function globalFunction(){
// do something here.
}
and access it anywhere by
$this->globalFunction();
You can define a static method as an option.
class core{
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
Then call it like so:
$val = core::convertToMyNotation($anotherval);
This requires no instantiation of the object to use. The only restriction is that you cannot use the $this property inside a static method.
Alternately, just define a file with your functions in it and include the file at some point early like, like within the boostrap script in your public_html/index.php file.
Edit: darkheir makes some good suggestions. Include such a class in your protected/components folder, and have it extend CComponent to gain some potentially useful enhancements.
By including the class in the protected/components folder, you gain the advantage of autoloading the class, by default.
There is no definitive question of your answer, it depends a lot on what the function will be doing!
If the function is performing some things specific to a model
(getting the last users, ...) this has to be in the User model as
Willem Renzema described:
class theModelClass {
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
And you'll call it like
$val = theModelClass::convertToMyNotation($anotherval);
If the function is handling user inputs (sanitizing he inputs,
checking the values, ...) then it has to go to the controller and
you'll use Hemc solution:
Create a public function in components/Controller.php
public function globalFunction(){
// do something here.
}
and access it anywhere by
$this->globalFunction();
If the function is an Helper: performing some actions that do not
depend on models or user inoput then you can create a new class that
you'll put in your component directory:
class core extends CComponent{
public static function convertToMyNotation($value){
//do whatever here
return $value;
}
}
And
$val = core::convertToMyNotation($anotherval);
Actually, I think you're looking for this answer instead:
http://www.yiiframework.com/wiki/31/use-shortcut-functions-to-reduce-typing/
In essence, in your entry script, before you load up Yii, include a global functions file:
require('path/to/globals.php');
Then, any function defined in that file can be used as a shortcut. Be careful, but enjoy the power! :-)
Create something like
Class Core extends CApplicationComponent{
public function doSomething(){}
}
and in config main.php
'components'=>array(
'core'=>array(
'class' => 'Core'
),
),
and now you can call whenever you want
Yii::app()->core->doSomething();

Mef, passing parameters to a module

I'm studying MEF and I'm not able to resolve a problem.
I have a main application, called MainMEF, and a simple module, called SimpleModule. This one consists of a single UserControl which is loaded dynamically.
When MainMEF starts up, I would be able to pass to the module a reference to main application contained into MainMEF.
How could I fix this?
Lots of questions regarding this already.
You could pass it after initialisation using a property:
How do I populate a MEF plugin with data that is not hard coded into the assembly?
Or use MEF constructor parameters:
MEF Constructor Parameters with Multiple Constructors
The export looks something like this:
[Export(typeof(ITest))]
class Test : ITest
{
void Test()
{ }
[ImportingConstructor] //<- This is the key bit here
void Test(object parameter)
{ }
}
Then when composing your catalog do this:
catalog.ComposeExportedValue( /* parameter here */);
catalog.ComposeParts(this);