In my TDD project I am trying to test a method in an abstract class.
abstract class Database_Mapper_Abstract
{
public function setTable($sTablename){
return('foo');
}
}
This is the way I wrote my simple test:
public function testCanSetTable(){
$oMock = $this->getMockForAbstractClass('JCMS_Database_Mapper_Abstract');
$oMock->expects($this->once())
->method('setTable')
->with($this->equalTo('foo'))
->will($this->returnValue('foo'));
$this->assertEquals('foo',$oMock->setTable());
}
When I run this test i get the following error:
PHPUnit 3.5.13 by Sebastian Bergmann.
E
Time: 1 second, Memory: 6.75Mb
There was 1 error:
1)
Database_Mapper_AbstractTest::testCanSetTable
Missing argument 1 for
Database_Mapper_Abstract::setTable(), called in
K:\xampp\htdocs\tests\library\Database\Mapper\Abstract.php
on line 15 and defined
K:\xampp\htdocs\library\Database\Mapper\Abstract.php:4
K:\xampp\htdocs\tests\library\Database\Mapper\Abstract.php:15
FAILURES! Tests: 1, Assertions: 0,
Errors: 1.
The way I understand this is that it can't find the argument for the setTable function.
But I set it with the with() method. I also tried with('foo'). That also doesn't help me.
Does anyone have an idea?
Testing an abstract class:
For testing an abstract class you don't want to use the "create behavior methods".
Just getMockForAbstractClass() like this:
<?php
abstract class JCMS_Database_Mapper_Abstract
{
public function setTable($sTablename){
return $sTablename."_test";
}
}
class myTest extends PHPUnit_Framework_TestCase {
public function testCanSetTable(){
$oMock = $this->getMockForAbstractClass('JCMS_Database_Mapper_Abstract');
$this->assertEquals('foo_test', $oMock->setTable('foo'));
}
}
You just use the mocking functionality to create an instance of that abstract class and test against that.
It's only a shortcut for writing
class MyDataMapperAbstractTest extends JCMS_Database_Mapper_Abstract {
// and filling out the methods
}
The actual error:
What happens is that you have a method with one parameter:
public function setTable($sTablename){
but you call it with zero paremters:
$oMock->setTable()
so you get an error from PHP and if PHP throws a warnings PHPUnit will show you an error.
Reproduce:
<?php
abstract class JCMS_Database_Mapper_Abstract
{
public function setTable($sTablename){
return('foo');
}
}
class myTest extends PHPUnit_Framework_TestCase {
public function testCanSetTable(){
$oMock = $this->getMockForAbstractClass('JCMS_Database_Mapper_Abstract');
$oMock->expects($this->once())
->method('setTable')
->with($this->equalTo('foo'))
->will($this->returnValue('foo'));
$this->assertEquals('foo',$oMock->setTable());
}
}
Results in:
phpunit blub.php
PHPUnit 3.5.13 by Sebastian Bergmann.
E
Time: 0 seconds, Memory: 3.50Mb
There was 1 error:
1) myTest::testCanSetTable
Missing argument 1 for JCMS_Database_Mapper_Abstract::setTable(), called in /home/.../blub.php on line 19 and defined
Fixing
Change:
$this->assertEquals('foo',$oMock->setTable());
to
$this->assertEquals('foo',$oMock->setTable('foo'));
then you don't get a PHP Warning and it should work out :)
Related
Update: with $stub = $this->createMock('Config'); this example works, but I get a warning:
OK, but incomplete, skipped, or risky tests! Tests: 1, Assertions: 0,
Risky: 1.
In the video-tutorial this example works without any warnings. Is it possible to fix this warning?
I can't find why I am getting this error and how to fix it. This code is from a video tutorial. And in the Video it works. Maybe a typo?
Error:
c:\laragon\www\phpunit λ phpunit --colors tests\DateFormatterTest.php
PHPUnit 6.0.0 by Sebastian Bergmann and contributors.
E 1
/ 1 (100%)
Time: 35 ms, Memory: 4.00MB
There was 1 error:
1) DateFormatterTest::testFormattingDatesBasedOnConfig Error: Call to
undefined method DateFormatterTest::getMock()
C:\laragon\www\phpunit\tests\DateFormatterTest.php:10
ERRORS! Tests: 1, Assertions: 0, Errors: 1.
Here my code:
Config.php
<?php
class Config {
public function get() {
return 'd-m-Y';
}
}
DateFormatter.php
class DateFormatter {
protected $config;
public function __construct (Config $config) {
$this->config = $config;
}
public function getFormattedDate($timestamp) {
return date($this->config->get('date.format'), $timestamp);
}
}
DateFormatterTest.php
<?php
use PHPUnit\Framework\TestCase;
require_once 'C:\laragon\www\phpunit\src\DateFormatter.php';
require_once 'C:\laragon\www\phpunit\src\Config.php';
class DateFormatterTest extends TestCase {
public function testFormattingDatesBasedOnConfig() {
$stub = $this->getMock('Config');
var_dump($stub);
}
}
getMock() no longer exists in PHPUnit 6. Use createMock() or getMockBuilder() instead.
I am trying to learn how to write tests using phpunit.
In the test case i am trying to write i am testing 3 methods. Test is if method 1 returns false then call method 2 and 3 else just stop.
class MyTest {
$mock1->getMock('some class1')
$mock1->expect($this->once())
->method('method1')
->will($this->returnValue(false));
$mock2->getMock('some_class2')
$mock2->expect($this->once())
->method('method2')
$mock2->method2($arg)
$mock2->expect($this->once())
->method('method3')
$mock3->method3($arg)
}
how do i test if method 2 and 3 were called.
Currently i am getting a failure that No Test was Found
Look at the documentation, roughly this is how your class should look like:
class MyTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
//initialize objects for each method to work with
}
public function testFeature()
{
$arg = 'something';
$mock1->getMock('some class1');
$mock1->expect($this->once())
->method('method1')
->will($this->returnValue(false));
$mock2->getMock('some_class2');
$mock2->expect($this->once())
->method('method2');
$mock2->method2($arg);
$mock2->expect($this->once())
->method('method3');
//$mock3->method3($arg);
}
}
I am new to PHP and trying to write a basic test case that verifies a connection to a database. Clearly I'm missing something fundamental. I understand from reading the manual online that this involves extending the PHPUnit_Extensions_Database_TestCase and implementing a couple of functions (getConnection() and getDataSet()). Please see my code below of the simplest case I could come up with to still get the head-scratching issue I'm encountering:
<?php
abstract class DBTest extends PHPUnit_Extensions_Database_TestCase
{
public function getConnection()
{
return true;
}
public function getDataSet()
{
return true;
}
}
?>
As you can see, the tests do nothing but return true. However, when I do a "phpUnit DBTest" I get the following message back:
PHPUnit 4.2.6 by Sebastian Bergmann.
F
Time: 1 ms, Memory: 7.50Mb
There was 1 failure:
1) Warning
No tests found in class "DBTest".
FAILURES!
Tests: 1, Assertions: 0, Failures: 1.
What am I missing? Any advice would help. Thanks.
PHPUnit complains about not finding any test. You must add at least a test method:
<?php
abstract class DBTest extends PHPUnit_Extensions_Database_TestCase
{
public function getConnection()
{
return true;
}
public function getDataSet()
{
return true;
}
public function testDummy()
{
$this->assertTrue(true);
}
}
?>
I am not sure if I am doing something wrong or it is a bug with PHPUnit and mock objects. Basically I am trying to test if $Model->doSomething() is called when $Model->start() is triggered.
I am using Ubuntu in a VirtualBox, and phpunit 1.1.1 installed via pear.
The full code is below. Any help would be appreciated, it's driving me crazy.
<?php
require_once 'PHPUnit/Autoload.php';
class Model
{
function doSomething( ) {
echo 'Hello World';
}
function doNothing( ) { }
function start( ) {
$this->doNothing();
$this->doSomething();
}
}
class ModelTest extends PHPUnit_Framework_TestCase
{
function testDoSomething( )
{
$Model = $this->getMock('Model');
$Model->expects($this->once())->method('start'); # This works
$Model->expects($this->once())->method('doSomething'); # This does not work
$Model->start();
}
}
?>
The output from PHPUnit:
There was 1 failure:
1) ModelTest::testDoSomething
Expectation failed for method name is equal to <string:doSomething> when invoked 1 time(s).
Method was expected to be called 1 times, actually called 0 times.
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
As you found, you need to tell PHPUnit which methods to mock. Also, I would avoid creating expectations for methods that you are calling directly from the test. I would write the above test like this:
function testDoSomething( )
{
$Model = $this->getMock('Model', array('doSomething');
$Model->expects($this->once())->method('doSomething');
$Model->start();
}
Just to expand on why David Harkness's answer works, if you do not specify the $methods parameter to getMock then all functions in the class are mocked. Incidentally, you can confirm this with:
class ModelTest extends PHPUnit_Framework_TestCase
{
function testDoSomething( )
{
$obj = $this->getMock('Model');
echo new ReflectionClass(get_class($obj));
...
}
}
So, why does it fail? Because your start() function has been mocked too! I.e. the function body you have given has been replaced, and so your $this->doSomething(); line never gets run.
Hence, when there are any functions in your class that you need to be preserved, you'll have to explicitly give the list of all other functions.
I wrote a little test case for a model I created in Yii and when I try to run the test, it gives me: Fatal error: Class
'.....\ActiveRecord' not found in Commissions.php'
Now, my class (commissions.php) inherits the ActiveRecord class in Yii but how can I tell PHPunit where to find it? I've tried using an include statement in Commissions.php but then it can't find the class that ActiveRecord inherits and so on.
<?php
include_once('Commissions.php');
class CommissionsTest extends PHPUnit_Framework_TestCase
{
// Here, the idea would be to check one or two employees manually or based on the SQL query
// Or even a previous value using the function so that when any changes are made, the value
// remains the same while using the same arguments.
public function setUp()
{
$this->employee = new Commissions();
$this->employee->employeeId = 'V1S';
$this->employee->year = 2012;
$this->employee->period = 1;
}
public function testAttributes()
{
$this->assertEquals('V1S', $this->employee->employeeId);
$this->assertEquals(2012, $this->employee->year);
$this->assertEquals(1, $this->employee->period);
}
}
?>
What you should have at the beginning of your testcase is:
Yii:import('application.models.Commissions'); //or whatever your model is called
class CommissionsTest extends CDbTestCase { //Not PHPUnit_Framework_TestCase