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.
Related
I have a function that exists within a controller.
I want to that the logic is sound by writing a small unit test with assertions to match correctly with the output of the function.
I've created a new unit folder to house all the little unit tests for the controller. The correct term may be a functional test?
This is the current set up I have to house all of the assertions for the function. My question is, out of all the functions that exist in this external controller, how can I bring that function in and perform a test on the logic within it?
<?php
namespace Acme\SimplewanBundle\Tests\Unit;
use Doctrine\ORM\Tools\SchemaTool;
class ConfigControllerUnitTest extends \PHPUnit_Framework_TestCase {
public function testValidIpRange() {
}
}
First, the method should probably be moved to a service independent from the controller. In any case, without doing that change, you can already test the controller class as any other PHP class:
namespace Acme\SimplewanBundle\Tests\Unit;
use Doctrine\ORM\Tools\SchemaTool;
class ConfigControllerUnitTest extends \PHPUnit_Framework_TestCase {
public function testValidIpRange()
{
$controller = new \AppBundle\Controller\ConfigController();
$this->assertTrue($controller->isValidIpRange(...));
}
}
Here's a test PHPUnit test I wrote:
<?php
class MyTest extends PHPUnit_Framework_TestCase
{
public function __construct()
{
echo "starting tests\r\n";
parent::__construct();
}
public function provider()
{
return array(array('test'));
}
/**
* #dataProvider provider
*/
public function testProvider($var)
{
$this->assertEquals($var, $var);
//exit($var);
}
}
When I run it I get the following:
There was 1 error:
1) MyTest::testProvider
Missing argument 1 for MyTest::testProvider()
/home/myname/test.php:19
FAILURES!
Tests: 1, Assertions: 0, Errors: 1.
My question is... why? And what can I do about it?
In the actual unit tests I'm writing (the above is just a test demonstrating the problem) I'm testing a class with several different backend engines. I have an abstract class with a bunch of test cases and a protected class variable named $engine. I then have a bunch of classes that extend this abstract class and set $engine in the constructor. In each of the test methods in the abstract method $obj->setEngine($this->engine) is then called to test the specific engine in question. But this approach seems to break unit tests with providers and in lieu of that I'm not sure what I should be doing.
Any ideas?
Instead of implementing a constructor, you should use the static method setUpBeforeClass to create the $engine. The engine must be stored in a static property.
https://phpunit.de/manual/current/en/fixtures.html#fixtures.sharing-fixture
A Simpletest test in MyTest.php that runs with no errors:
require_once ('simpletest/autorun.php');
class MyTest extends UnitTestCase {
function test() {
//Test...
}
}
A SimpleTest test suite
require_once ('simpletest/autorun.php');
class AllTests extends TestSuite {
function __construct() {
$this->TestSuite('All tests');
$this->addFile('MyTest.php');
}
}
The error:
Fatal error: Cannot redeclare simpletest_autorun() (previously declared in /Library/WebServer/Documents/Option/tests/simpletest/autorun.php:26) in /Library/WebServer/Documents/option/tests/simpletest/autorun.php on line 34
The (horrible) solution, change MyTest.php to:
if (!function_exists("simpletest_autorun")) {
require_once ('simpletest/autorun.php');
}
class MyTest extends UnitTestCase {
function test() {
//Test...
}
}
It appears that this example follows the documentation, it doesn't or SimpleTest has this bug?
I can only assume you have multiple copies of the SimpleTest autorun.php script.
Performing the require in your test case file attempts to include a second autorun.php file (different to the one included in your test suite) which defines simpletest_autorun() for the second time.
The fact that the line numbers don't match up adds credence to my assumption.
Looking at the full paths in the error messages should show you what's up.
Determine which copy you want to keep and remove the other, updating any incorrect paths in your code or configuration, including the include_path in php.ini.
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
}
}
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