I have this test in tests\api\LoginCest.php:
class LoginCest {
public function login( ApiTester $I ) {
$I->assertTrue( true );
}
}
and this test in a different class, tests\api\UpdateUserCest.php:
class UpdateUserCest {
/**
* #depends LoginCest:login
*/
public function updateUser( ApiTester $I ) {
$I->assertTrue( true );
}
}
Note that in the #depends annotation I'm using the first test signature LoginCest:login, as suggested in the Codeception docs:
#depends applies to the Cest and Codeception\Test\Unit formats.
Dependencies can be set across different classes. To specify a
dependent test from another file you should provide a test signature.
Normally, the test signature matches the className:methodName format.
But to get the exact test signature just run the test with the --steps
option to see it:
I have verified that the signature for the first test is LoginCest:login. However when I run the second test it fails because it says the first test was skipped. More precisely, the console says:
UpdateUserCest: Update user Signature: UpdateUserCest:updateUser Test:
tests/api/UpdateUserCest.php:updateUser
Scenario --
SKIPPED: This test depends on LoginCest:testLogin to pass
and then:
There was 1 skipped test:
--------- 1) UpdateUserCest: Update user Test tests/api/UpdateUserCest.php:updateUser This test depends on
LoginCest:login to pass
OK, but incomplete, skipped, or risky tests! Tests: 1, Assertions: 0,
Skipped: 1.
What am I missing?
#depends mean, that the test only is being executed, if the one, which you are depending on was passing successfully.
So if you want to call "login" before you call "updateUser" in your example, you should use the annotation #before.
The second thing is, that I guess that this behaviour only work, if both methods are in the same test class. So this should be work:
class UpdateUserCest
{
public function login(ApiTester $I)
{
$I->assertTrue(true);
}
/**
* #before login
*/
public function updateUser(ApiTester $I)
{
$I->assertTrue(true);
}
}
now you can explicitly run your update user test and can be sure, the login method is called before.
codecept.phar run test/api/UpdateUserCest.php:updateUser
Per AdvancedUsage - Codeception 4 Documentation
To specify a dependent test from another file you should provide a test signature.
Normally, the test signature matches the className:methodName format.
But to get the exact test signature just run the test with the --steps
option to see it
Usually test signature is:
Signature: LoginCest:login
But note, that the signature can also contain a namespace:
Signature: MyProject\Tests\LoginCest:login
Make sure you use proper test signature. Run the tests with --steps option and copy the test signature from there.
Codeception indeed sort tests based on dependencies, and this is great feature to use.
Related
I want to skip only one test in a codeception cest test.
Using Cept tests you can do $scenario->skip(); but does not work for Cest tests.
So I want to do something like this. Run the first test, but skip the second one.
Class MyTests{
public funtion test1(){
// My test steps
}
public function test2(){
$scenario->skip("Work in progress");
}
}
Thank you in advance.
the method you are looking for is called "incomplete".
$scenario->incomplete('your message, why skipping');
If you want to use Scenarios in Cest files, you can get it with the second parameter of your test method:
class yourCest
{
public function yourTest(WebGuy $I, $scenario)
{
$scenario->incomplete('your message');
}
}
Or you can use $scenario->skip('your message')
class yourCest
{
public function yourTest(WebGuy $I, $scenario)
{
$scenario->skip('your message');
}
}
Edit:
As already mentioned, the WebGuy is outdated and the annotations #skip or #incomplete are the way you should skip your tests in Cest files.
class yourCest
{
/**
* #skip Skip message
*/
public function yourTest(AcceptanceTester $I)
{
$I->shouldTestSomething();
}
}
I use the skip annotation for my unit tests.
/**
* #skip
*/
public function MyTest(UnitTester $I)
{
...
}
First of all, remember that which commands are available to you are going to depend on which modules and suites you have loaded. For instance, if you are doing integration tests with the default WordPress enabled YML:
$scenario->skip('your message');
won’t work in a Cest or Test out of the box, but will work in Acceptance.
In fact, generally this command will work with Cept tests [Cepts are usually Acceptance like tests, Cests and Tests are usually PHPUnit like OOP tests]. Also, you need to pass $scenario to your function. This isn’t clearly documented and I can’t get it to work in Cests. Don’t get me started on how bad a choice “$scenario” is as a keyword for a BDD framework! A “scenario” is a keyword in Gherkin referring to what is a “step object” in Codeception. In Codeception it seems to be used as a redundant form of “environment”, even though there are environments, suites, and groups already. Like most of this great framework, the docs and function names need to be redone by native English speakers, for the second time! [remember “web guy”? Damn sexists Europeans! Lol].
If you use the
/**
* #skip
*/
public function myTest(){
//this test is totally ignored
}
Annotation right above your function in a Cest or Test it will be skipped, and won’t even appear in the report. [REALLY skip it]. Use this if you want to compleately hide a test.
If you use the PHPUnit command directly:
public function myTest(){
throw new \PHPUnit_Framework_SkippedTestError('This test is skipped');
//this test will appear as a yellow “skipped” test in the report
}
This will generate a skipped test in the report, will turn yellow in the HTML report [--html]. Use this if you want to skip a test but notice in the report that it’s skipped.
Use PHPUnit_Framework_SkippedTestError. For example:
if (!extension_loaded('mongo')) {
throw new \PHPUnit_Framework_SkippedTestError(
'Warning: mongo extension is not loaded'
);
}
So to make your scenario skipped during test run :
You must have $scenario as second input param in your test
make call : $scenario->skip();
make call after skip : $I->comment("Reason why scenario skipped")
I'm currently testing a wrapper to an API with PHPUnit (CLI).
Due to the nature of the tests, I can pretty much use the same code for testing two different use cases. The only difference is in the values I send to the API as parameters.
So, I decided to write a class DefaultTest, where I test the API using default values used by the API and a second CustomTest(Case) where I test my parameter container with differing values. CustomTest inherites from DefaultTest, as all the functions used for validating the returned data are equivalent in both cases.
Here's some code for your understanding:
class DefaultTest extends PHPUnit_Framework_TestCase {
public function testAPIMethod()
{
$this->checkParameterContainer();
$this->validateResults();
}
public function checkParameterContainer()
{
/* Set up default parameter container */
}
public function validateResults()
{
/* Validate the results */
}
}
class CustomTest extends DefaultTest {
public function checkParameterContainer()
{
/* Set up custom parameter container */
}
public function validateResults()
{
parent::validateResult();
}
}
PHPUnit takes the child class, executes the testAPIMethod, leading to CustomTest::checkParameterContainer() and DefaultTest::validateResults() being executed.
But DefaultTest's testAPIMethod is never executed, as DefaultTest::checkParameterContainer() is never called.
Both classes are fully valid TestCases and DefaultTest is executed normally when not specialized.
So, my question for you guys: Why is that? Do I miss something here? Is this by design?
In case, somebody needs it: PHPUnit uses reflection to find test methods on each class, but will not search in parent classes. So the following will be needed in the child test class:
public function testAPIMethod()
{
parent::testAPIMethod();
}
I have a PHPUnit test case class (consisting of some test functions). I would like to write a oneTimeSetUp() function to be called once for all my tests in the class (unlike the standard setUp() function which is called once for each test in the class). In other words, I'm looking for a PHPUnit equivalent to the JUnit #BeforeClass annotation.
Same question with a oneTimeTearDown() function.
Is it possible to do so in PHPUnit?
Take a look at setUpBeforeClass() from section 6 of the PHPUnit documentation.
For the one time tearDown you should use tearDownAfterClass();.
Both this methods should be defined in your class as static methods.
setUpBeforeClass() is the way to do this if all of your tests are literally contained within a single class.
However, your question sort of implies that you may be using your test class as a base class for multiple test classes. In that case setUpBeforeClass will be run before each one. If you only want to run it once you could guard it with a static variable:
abstract class TestBase extends TestCase {
protected static $initialized = FALSE;
public function setUp() {
parent::setUp();
if (!self::$initialized) {
// Do something once here for _all_ test subclasses.
self::$initialized = TRUE;
}
}
}
A final option might be a test listener.
I came to this page with the same question, however the accepted answer is ran on all classes, and for me was not the correct answer.
If you are like me, your first "Integration test" is to clear out the DB, and run migrations. This gets yourself at a database baseline for all test. I am constantly changing migration files at this point, so setting up the baseline is truly part of all tests.
The migration takes a while, so I do not want it run on all tests.
Then I needed to build up the database testing each piece. I need to write an order test, but first I need to create some products and test that, then I need to test an import fuction.
So, what I did is SUPER easy, but not explained extremely well on the internet. I created a simple test to setup the database. Then in your phpspec.xml file add a testsuite....
<testsuite name="Products">
<file>tests/in/SystemSetupTest.php</file>
<file>tests/in/ProductTest.php</file>
<file>tests/in/ProductImportTest.php</file>
</testsuite>
And in the the SystemSetupTest.php ....
class SystemSetupTest extends ApiTester
{
/** #test */
function system_init()
{
fwrite(STDOUT, __METHOD__ . "\n");
self::createEM(); //this has all the code to init the system...
}
}
Then execute it like:
phpunit --testsuite Products
In the end, its a ton easier. It will allow me to build up my system correctly.
Additionally I am using laravel 5. When using setUpBeforeClass() I end up with bootstrap issues, which I am sure I can fix, but the method I use above works perfect.
The bootstrap option can be used on these cases.
You can call it from the command line
phpunit --bootstrap myBootstrap.php
Or put it in the XML file, like this:
<phpunit bootstrap="myBootstrap.php">
...
</phpunit>
Expanding on accepted answer:
None of the setUpBeforeClass(), tearDownAfterClass(), #beforeClass, #afterClass runs in the object context (static methods). You can work around that restriction by guarding any #before code with a static property instead, like so:
class MyTest extends PHPUnit\Framework\TestCase
{
private static $ready = false;
/**
* #before
*/
protected function firstSetUp()
{
if (static::$ready))
return;
/* your one time setUp here */
static::$ready = true;
}
}
It can't be used for #after, however, because there's no way of saying when the last test was called.
I'm using PHPUnit to test a class that has many functions.
The PHPUnit framework runs the test functions from the top to the bottom.
The question is: How can I run the test functions in a specified order without reorder then in the source code.
To clarify the issue, imagine we have 5 test functions;
testFunc1
testFunc2
testFunc3
testFunc4
testFunc5
The framework will run testFunc1 then testFunc2 until it reaches testFunc5.
However, I want to run testFunc3 then testFunc1 then testFunc5 then testFunc2 then testFunc4 without reordering them in the source file.
PHPUnit will execute the tests in the exact order they are written in your *_TestCase class.
Every one of those tests should be able to run in isolation and not depend on some other test beeing executed before it.
If you have issues testing against a Database I'd suggest using somethig like this:
class MyTest extends PHPUnit_Framework_TestCase {
public function setUp() {
// REPLACE INTO testDb (ID, NAME, VALUE) VALUES (1001000, 'testing', 'value')
$this->db = $db_connection;
}
public function tearDown() {
// DELETE FROM testDb WHERE ID > 10010000 // or something like this
}
public function testSelect() {
$this->assertSame("value", $this->db->getId(100100));
}
/**
* #depends testSelect
*/
public function testInsert() {
$this->db->insertById(1001111, "mytest", "myvalue");
$this->db->getId(1001111);
}
/**
* #depends testSelect
*/
public function testDelete() {
$this->db->deleteById(1001000);
$this->assertNull($this->db->getId(10010000);
}
// and so on
}
The setUp() method will be run before every testcase and make sure all the values most testcases need are there, the tearDown() will clean up after the testsuite.
The #depends annotation will make sure that the insert test isn't run when the select test fails. (If you can't load values then inserting new ones and getting those can't work ether, no need to try it).
For that also check the manual on test dependencies
The whole point of unit tests are actually in the name itself, Unit Testing. They function on their own and have no dependencies whatsoever on each other. If you code your tests right, order of execution should not matter.
If it is a matter of a database issue, make sure you have a clean database before every test.
Right now there's no way to do it short of reordering the functions in the file. There's a feature request to use the #depends annotations to reorder the tests, and the PHPUnit author has expressed a desire to do it. You can comment on the request at PHPUnit's github tracker.
I've already read the documentation. Basically I've tried tests while following the BankAccount example.
But I get errors:
Warning: require_once(PHP/CodeCoverage/Filter.php) [function.require-once]: failed to open stream: No such file or directory in [...]/unitTest/phpunit.php on line 38
Also, the PHP scripts seems to start with #!/usr/bin/env php which indicate they should be run from the console. I'd rather run these from the browser...
Suppose I have a function f1() that returns a string. How should the tests be made? Am I missing something?
A short introduction to the test framework
PHPUnit provides a simple framework for creating a test suite to automate testing of functions and classes. PHPUnit is inspired by JUnit which was created by Kent Beck and Erich Gamma as a tool for eXtreme Programming. One of the rules of XP is to test small software components as often and early as possible, this way you will not have to fix bugs and errors in the API while setting up and testing larger applications which depend on the class. While unit testing is one of the fundimental rules in XP, you don't have to switch to XP to benefit from PHPUnit. PHPUnit stands alone as a good tool for testing classes or a set of functions and will ease your development cycle and help you to avoid endless debug sessions.
Work routine
Normally, you would write a class, do some unsystematic tests using echo() or var_dump(). After this, you use the class in your application and hope everything is ok. To benefit from PHPUnit you should rethink the flow. The best way is to do this:
design your class/API
create a test suite
implement the class/API
run the test suite
fix failures or errors and go to #4 again
It may seem that this will require a lot of time, but this impression is wrong. Creating the test suite using PHPUnit needs only a few minutes and running the test suite only seconds.
Design a class
Let's start with a small example: a string class. First we create a bunch of functions declarations to work on a string:
---- string.php ----
<?php
class String
{
//contains the internal data
var $data;
// constructor
function String($data) {
$this->data = $data;
}
// creates a deep copy of the string object
function copy() {
}
// adds another string object to this class
function add($string) {
}
// returns the formated string
function toString($format) {
}
}
?>
Creating test suite
Now we can create a test suite, which checks every function of your string class. A test suite is normal PHP class inherited from PHPUnit_TestCase containing test functions, identified by a leading 'test' in the function name. In the test function an expected value has to be compared with the result of the function to test. The result of this compare must delegate to a function of the assert*()-family, which decides if a function passes or fails the test.
---- testcase.php ----
<?php
require_once 'string.php';
require_once 'PHPUnit.php';
class StringTest extends PHPUnit_TestCase
{
// contains the object handle of the string class
var $abc;
// constructor of the test suite
function StringTest($name) {
$this->PHPUnit_TestCase($name);
}
// called before the test functions will be executed
// this function is defined in PHPUnit_TestCase and overwritten
// here
function setUp() {
// create a new instance of String with the
// string 'abc'
$this->abc = new String("abc");
}
// called after the test functions are executed
// this function is defined in PHPUnit_TestCase and overwritten
// here
function tearDown() {
// delete your instance
unset($this->abc);
}
// test the toString function
function testToString() {
$result = $this->abc->toString('contains %s');
$expected = 'contains abc';
$this->assertTrue($result == $expected);
}
// test the copy function
function testCopy() {
$abc2 = $this->abc->copy();
$this->assertEquals($abc2, $this->abc);
}
// test the add function
function testAdd() {
$abc2 = new String('123');
$this->abc->add($abc2);
$result = $this->abc->toString("%s");
$expected = "abc123";
$this->assertTrue($result == $expected);
}
}
?>
The first test run
Now, we can run a first test. Make sure that all the paths are correct and then execute this PHP program.
---- stringtest.php ----
<?php
require_once 'testcase.php';
require_once 'PHPUnit.php';
$suite = new PHPUnit_TestSuite("StringTest");
$result = PHPUnit::run($suite);
echo $result -> toString();
?>
If you call this script from the commandline, you will get the following output:
TestCase stringtest->testtostring() failed: expected true, actual false
TestCase stringtest->testcopy() failed: expected , actual Object
TestCase stringtest->testadd() failed: expected true, actual false
Every function fails the test, because your string functions didn't returned what we defined as the expected value.
If you want to call the script through your browser, you have to put the script in a correct html page and call $result->toHTML() instead of $result->toString().
Implementation
Ok, let's start with implementation of the our string class.
---- string.php ----
<?php
class String
{
//contains the internal data
var $data;
// constructor
function String($data) {
$this->data = $data;
}
// creates a deep copy of the string object
function copy() {
$ret = new String($this->data);
return $ret;
}
// adds another string object to this class
function add($string) {
$this->data = $this->data.$string->toString("%ss");
}
// returns the formated string
function toString($format) {
$ret = sprintf($format, $this->data);
return $ret;
}
}
?>
The implementation is complete and we can run the test again:
~>
php -f stringtest.php
TestCase stringtest->testtostring() passed
TestCase stringtest->testcopy() passed
TestCase stringtest->testadd() failed: expected true, actual false
D'oh! the last test failed! We made a typing mistake. Change line 16 in string.php to
<?php
$this->data = $this->data.$string->toString("%s");
?>
and run the test again:
~>
php -f stringtest.php
TestCase stringtest->testtostring() passed
TestCase stringtest->testcopy() passed
TestCase stringtest->testadd() passed
Everything is now OK!
Conclusion
Does it seem like a lot of work for testing three simple functions? Don't forget, this is a small example. Think about bigger, more complex API's like database abstraction or basket classes in a shop application. PHPUnit is an excellent tool to detect errors in the implementation of your class.
Often you will want to reimplement or refactor a large class which is used in several different applications. Without a test suite the likeliness of you breaking something in one of the applications that depends on your class is very high. Thanks to unit tests, you can create a test suite for your class, and then reimplement your class with the security of knowing that as long as the new class passes the tests, applications that depend on the class will work.
Used source: http://pear.php.net
I would really recomment running PHPUnit from Command Line, if possible. At our Company, it is not possible, but we are trying, wich makes our Tests unstable ...
I assume you have to setup some include paths for php with set_include_path(), so phpunit finds the rest of your files. But that may not be enough ...
Our code looks something like this
// you will have to write your own class here that collects the tests
$collector = new Unit_Test_Collector();
$suite = $collector->getSuite();
//$config is an array of phpunit config options
PHPUnit_TextUI_TestRunner::run($suite, $config);