I am using PHPUnit and Selenium to test my web application.
At the moment I have 2 test classes - UserTest and PermissionsTest.
In UserTest I have methods which test that the program can successfully create a new user.
In PermissionsTest I turn certain permissions on and off and test the outcome.
For instance, I might turn the 'Create User' permission off and then test that the 'Create User' button is disabled. However, if I turn the 'Create User' permission back on, I want to test that it is possible to create a user.
All of the logic for being able to create a user is already in the UserTest class - so is there any way of running tests from the UserTest class from the PermissionsTest class?
At the moment I am trying the following code:
public function testUserPermission(){
$userTest = new UserTest();
if($this->hasPermission = true){
$userTest->testCanCreateUser();
}
}
However when I run this test, I get the error "There is currently no active session to execute the 'execute' command. You're probably trying to set some option in setup() with an incorrect setter name..."
Thanks!
It sounds to me like you're missing separation of your test implementation with its logic - I'm not talking about PHP issue but general test model.It will allow you to reuse your test components in various test cases.
You can take a look on some
material about Page Objects in PHP here or general selenium wiki.
The solution was as follows:
//instantiate and set up other test class
$userTest = new UserTest();
$userTest->setUpSessionStrategy($this::$browsers[0]);
$userTest->prepareSession();
//carry out a test from this class
$userTest->testCanCreateUser();
This works nicely. I can't see why using functionality from another test class is a bad idea in this case, because if I didn't do that I'd have to just rewrite that functionality into my new class, which seems less 'pure'...
For Selenium 1 (RC),
I made the following modifications instead (as well as applying the Page Object design pattern):
Specific Test class
//instantiate and set up other test class
$userTest = new UserTest($this->getSessionId());
//carry out a test from this class
$userTest->createUser();
//asserts as normal
$userTest->assertTextPresent();
...
Base Page Object class
class PageObject extends PHPUnit_Extensions_SeleniumTestCase {
public function __construct($session_id) {
parent::__construct();
$this->setSessionId($session_id);
$this->setBrowserUrl(BASE_URL);
}
}
Specific Page Object class
class UserTest extends PageObject {
public function createUser() {
// Page action
}
}
Related
I was writing a custom class to handle some unique operations in my project, which is developed in Laravel 5.2. In that, I've called some existing model functions also to fetch some values from the database. If we run the code, it'll work fine. But when I wrote different test cases and tested those classes alone, a database connection error has occurred, as the connection was not established.
PHP Fatal error: Call to a member function connection() on null in /var/www/html/****/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 3314
I could write a separate test code to create and delete resources in the database. But that is not what I'm searching for. I wanted to use custom functions written in the model class like shown below.
<?php
namespace ****\Paymentmethod;
use App\Models\Customer;
/**
* ****** Package - Additional helpers
* #package *******
* #author ********
*
* Card is intended to handle the operations related to credit cards
*
*/
class Card
{
private $var;
public function __construct()
{
//constructor
}
public static function getCard($user_id)
{
return Customer::getCustomerInfo($user_id);
}
}
This Card class is used in another class and that is what I'm testing.
Customer is a model class and getCustomerInfo is a custom method in it.
You're app instance is probably not instantiated.
Have a look at the TestCase.php that Laravel provides in the tests/ folder, it creates an instance of the app. Unless your test is a pure 'unit' test which does not rely on the framework at all, you need to make sure your test extends the TestCase class so that it too will instantiate an application instance.
The reason it works when you run outside of the tests is when you enter the application via a route or a console command, the application is bootstrapped for you.
I am aware of the _bootstrap.php file that's used to set up the testing enviroment, etc., but I'm looking for a way to run some code after the entire test suite has finished.
Note that I'm not looking for a way to run code after a single class, i.e. something like _after, but after all classes.
Is there a way to achieve this?
Actually managed to solve this myself, here's how, if anyone is interested.
I created a new helper class inside _support.
<?php
class DataHelper extends \Codeception\Module
{
public function _beforeSuite()
{
// Set up before test suite
}
public function _afterSuite()
{
// Tear down after test suite
}
}
You can then enable this as a module in any suite configuration (the .yml files), like this:
modules:
enabled:
- DataHelper
#Sacha's solution is specially useful if you want to share the same methods accross all suites.
If you're looking for a way to define the methods for a specific suite (or if you want a different method per suite), you can define those methods directly in the suite Helper class.
For instance, if you want to define a _afterSuite method for the Acceptance Suite, just go to support/AcceptanceHelper.php and define those methods there. Eg:
<?php
namespace Codeception\Module;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
class AcceptanceHelper extends \Codeception\Module
{
public function _afterSuite() {
die('everything done');
}
}
I'm running into an error while trying to run some simple tests with SimpleTest for PHP.
Currently, I'm extending the class UnitTestCase as per the documentation. I'm trying to test different aspects of my class within a method. Here is my class:
<?php
class SimpleClass extends UnitTestCase {
public function __construct() {
$this->test();
}
private function test() {
$x = true;
$this->assertTrue($x, 'x is true');
}
}
I've tried extending the TestSuite class and using the syntax in the documentation but I got the same error:
Fatal error: Call to a member function getDumper() on a non-object in /simpletest/test_case.php on line 316
Any ideas on how I could do this or am I approaching class testing wrong?
Don't use a constructor in your test!
SimpleTest allows you to create classes with methods. If their name starts with "test", it is automatically recognized as a testing method that will get called if you start the test suite.
You created a constructor which calls your test method, and does an assertion without all the setup taking place, so SimpleTest does not have a reporter class that is needed to wrap it's test findings into a nice output.
Read the tutorial more closely, and you'll find some hints on how to set up a test suite or how to start a single test:
Let us suppose we are testing a simple file logging class called Log in classes/log.php. We start by creating a test script which we will call tests/log_test.php and populate it as follows...
Code example adapted from the documentation:
<?php
require_once('simpletest/autorun.php');
require_once('../classes/log.php');
class TestOfLogging extends UnitTestCase {
function testLogCreatesNewFileOnFirstMessage() {
$this->assertTrue(true);
}
}
?>
Note there is no constructor, and the autorun file will take care to run the test if this file is executed with PHP.
I'm trying to get Mockery to assert that a given method is called at least once.
My test class is:
use \Mockery as m;
class MyTest extends \PHPUnit_Framework_TestCase
{
public function testSetUriIsCalled()
{
$uri = 'http://localhost';
$httpClient = m::mock('Zend\Http\Client');
$httpClient->shouldReceive('setUri')->with($uri)->atLeast()->once();
}
}
As you can see, there's one test that (hopefully) creates an expectation that setUri will be called. Since there isn't any other code involved, I can't imagine that it could be called and yet my test passes. Can anyone explain why?
You need to call Mockery:close() to run verifications for your expectations. It also handles the cleanup of the mockery container for the next testcase.
public function tearDown()
{
parent::tearDown();
m::close();
}
To avoid having to call the close method in every test class, you can just add the TestListener to your phpunit config like so:
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener"></listener>
</listeners>
This approach is explained in the docs.
One thing to note from the linked docs is:
Make sure Composer’s or Mockery’s autoloader is present in the bootstrap file or you will need to also define a “file” attribute pointing to the file of the above TestListener class.
Just a sidenote: If you use Laravel: the make:test --unit generates a test class that extends the original PhpUnit Testcase class and not the included Tests\Testcase, which loads the laravel app and runs the Mockery::close(). It is also the reason why in some cases your tests fail if you use Laravel specific code (like Cache, DB or Storage) in the units you're testing.
so if you need to test units with Laravel specific code, just swap out the 'extends Testcase' and there is no need to call Mockery::close() manually
I have a nice functioning CakePHP 1.3.11 site and I need a scheduled maintenance CLI script to run, so I'm writing it in PHP. Is there any way to make a cake-friendly script? Ideally I could use Cake's functions and Cake's Database models, the CLI requires database access and not much else however. I would ideally like to include my CLI code in a controller and the datasource in a model so I can call the function like any other Cake function, but only from the CLI as a sheduled task.
Searching for CakePHP CLI mostly brings results about CakeBake and cron jobs; this article sounded very helpful but it's for an old version of cake and requires a modified version of index.php. I'm no longer sure how to change the file to make it work in the new version of cakePHP.
I'm on Windows if it matters, but I have complete access to the server. I'm currently planning to schedule a simple cmd "php run.php" style script.
Using CakePHP's shells, you should be able to access all of your CakePHP app's models and controllers.
As an example, I've set up a simple model, controller and shell script:
/app/models/post.php
<?php
class Post extends AppModel {
var $useTable = false;
}
?>
/app/controllers/posts_controller.php
<?php
class PostsController extends AppController {
var $name = 'Posts';
var $components = array('Security');
function index() {
return 'Index action';
}
}
?>
/app/vendors/shells/post.php
<?php
App::import('Component', 'Email'); // Import EmailComponent to make it available
App::import('Core', 'Controller'); // Import Controller class to base our App's controllers off of
App::import('Controller', 'Posts'); // Import PostsController to make it available
App::import('Sanitize'); // Import Sanitize class to make it available
class PostShell extends Shell {
var $uses = array('Post'); // Load Post model for access as $this->Post
function startup() {
$this->Email = new EmailComponent(); // Create EmailComponent object
$this->Posts = new PostsController(); // Create PostsController object
$this->Posts->constructClasses(); // Set up PostsController
$this->Posts->Security->initialize(&$this->Posts); // Initialize component that's attached to PostsController. This is needed if you want to call PostsController actions that use this component
}
function main() {
$this->out($this->Email->delivery); // Should echo 'mail' on the command line
$this->out(Sanitize::html('<p>Hello</p>')); // Should echo <p>Hello</p> on the command line
$this->out($this->Posts->index()); // Should echo 'Index action' on the command line
var_dump(is_object($this->Posts->Security)); // Should echo 'true'
}
}
?>
The whole shell script is there to demonstrate that you can have access to:
Components that you load directly and that are not loaded through a controller
Controllers (first import the Controller class, then import your own controller)
Components that are used by controllers (After creating a new controller, run the constructClasses() method and then the particular component's initialize() method as shown above.
Core utility classes, like the Sanitize class shown above.
Models (just include in your shell's $uses property).
Your shell can have a startup method that is always run first, and the main method, which is your shell scripts main process and which is run after the startup.
To run this script, you would enter /path/to/cake/core/console/cake post on your command line (might have to check the proper way to do this on Windows, the info is in the CakePHP book (http://book.cakephp.org).
The result of the above script should be:
mail
<p>Hello</p>
Index action
bool(true)
This works for me, but maybe people who are more advanced in CakePHP shells could offer more advice, or possibly correct some of the above... However, I hope this is enough to get you started.
As of CakePHP 2, the shell scripts should now be saved to \Console\Command. There is good documentation at http://book.cakephp.org/2.0/en/console-and-shells.html