I've created a database testing class for one of my modules. When I try to run a test case, the initial fixture is not set up - all the tables in the testing database are empty. Here is my getDataSet() method:
/**
* #return PHPUnit_Extensions_Database_DataSet_IDataSet
*/
public function getDataSet()
{
return $this->createFlatXMLDataSet(dirname(__FILE__).'/dataSets/initial.xml');
}
I found out that the getDataSet() method gets called, because when I create a syntax error in it, the test execution fails. But when I create errors in file initial.xml, nothing happens. It seems like the file initial.xml is not being parsed at all!
The path to the file should be OK, but I noticed that when I enter an invalid path, again, nothing happends. Apparently, method createFlatXMLDataSet() does not throw any exception when something is wrong. So now I don't have any clue of why it doesn't work :(
RESOLVED: It turned out that getDataSet() was not called, because I've overriden setUp() and didn't realize that I should call parent::setUp() from the overriden method body.
So the conclusion is: If you are overriding method setUp(), you always have to call parent::setUp().
Related
I've been debugging line per line and it seems the error comes when I try to bind a repository to a mock:
$mock = Mockery::mock('MyNamespace\Repositories\MyModelInterfaceRepository');
// Error is in this line
$this->app->instance('MyNamespace\Repositories\MyModelInterfaceRepository', $mock);
I already bound repo interface and implementation and it works on the browser, it only fails in the test case, giving me an error 500.
My controller's constructor goes like this:
use MyNamespace\Repositories\MyModelInterfaceRepository;
class MyController extends Controller {
public function __construct(MyModelInterfaceRepository $repo) {
$this->repo = $repo;
}
....
Any ideas?
Edit:
Here is the log. It seems to be something about the View not receiving a proper foreach argument, which is possibly caused because the mock call is returning null.
For anyone who also encounters this problem, in this case, should the controller validate if the returned value is null (considering Eloquent would return an empty array if no records, but never null), or should the Mockery make sure it returns a value?
I have a unit test that is running a seeder I've constructed to create a new instance of one of my classes. When I run the seeder from Artisan, it runs without issue. However, when the unit test does it:
class MyClassTest extends TestCase {
public function setUp() {
// Setup application
parent::setUp();
$this->seed('MyClassSeeder');
}
... the following bit that gets run refuses to use the prefix!
class MyClass extends Base {
// Switch to the proper DB prefix
protected function prefix() {
DB::connection('main')->setTablePrefix($this->id . '_');
return $this;
}
// This is run by the seeder, everything up to here works fine...
public function setupDatabase() {
$this->prefix();
// This returns "1001_", which is correct
Log::info(Schema::connection('main')->getConnection()->getTablePrefix());
// Creates "myTable" instead of "1001_myTable"
if(!Schema::connection('main')->hasTable('myTable')) {
Schema::connection('main')->create('myTable', function($table) {
...
As it works fine when I run it manually, I'm not even sure where to start looking. It's even returning the proper prefix, just not using it. Has anyone else seen this? Is it reproducible? Is the testing environment (automatically used by unit tests) turning something off other than the filters, which I've already re-enabled?
Any help would be appreciated. Even a reproduction would at least tell me it's not our code. We've extended quite a bit, but there should be no major changes to the Laravel codebase on our install.
FURTHER TESTING
So I continued my testing, and found what appears to be a bug, though I'm going to look into it further, I'm posting it here in case it jogs anyone's memory for a similar issue:
I modified
Log::info(Schema::connection('main')->getConnection()->getTablePrefix());
to be
Log::info('Grammar Prefix: ' . Schema::connection('promotion')->getConnection()->getSchemaGrammar()->getTablePrefix());
Log::info('Connection Prefix: ' . Schema::connection('promotion')->getConnection()->getTablePrefix());
And found that while the Connection Prefix line works properly as it did before, the Grammar's Prefix is non-existent. The Grammar and Connection prefixes don't match. While I can work around this, I'd like to know why it's held consistent when I run it in any way other than through the unit testing class, but there's a mismatch here. Will be reporting as a bug soon if it appears that way to anyone else.
FINAL TESTING
From what I can tell, the code should get the initial settings from it's database config file, and then both the Blueprint and Schema should use the updated prefix when the line
DB::connection('promotion')->setTablePrefix($this->id . '_');
is run. I've worked around it by also running the line
DB::connection('promotion')->getSchemaGrammar()->setTablePrefix($this->id . '_');
Which seems to fix the issue. This shouldn't be necessary, and I see no reason the code I'm using should not have the desired effect. I'm considering this a bug, and will report it later today. I'll leave the question open for a bit in case I'm missing something, but I'll close it soon.
I've come to the conclusion this is a bug. There's no explanation why it would work in one environment but not the other unless Testing is doing something different than a default environment, and I can't find it.
PHPUnit doesn't change anything to how Laravel interacts with the database. Make sure that your configuration is not overridden when you run tests by any environment configuration
Also make sure you are setting and using the same connection . In the code you provided, you are setting up the prefix for connection promotion, yet you are using connection main
Here is an example that works, i tried to make it as similar as yours.
TestSeedTest.php
<?php
class TestSeedTest extends TestCase{
public function setUp() {
// Setup application
parent::setUp();
}
public function testSeeder(){
$this->seed('MyClassSeeder');
}
}
?>
MyClassSeeder.php
<?php
class MyClassSeeder extends Seeder {
private $id='123';
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$this->setupDatabase();
}
protected function prefix() {
DB::connection('promotion')->setTablePrefix($this->id . '_');
return $this;
}
// This is run by the seeder, everything up to here works fine...
public function setupDatabase() {
$this->prefix();
if(!Schema::connection('promotion')->hasTable('myTable')) {
Schema::connection('promotion')->create('myTable', function($table) {
$table->increments('id');
$table->string('test');
$table->timestamps();
});
}
}
}
I seem to be having some trouble testing that a private instance variable was set. My idea was to stub out the class and make the instance variable public so I could test the setter method. This seems simple enough, but I can't seem to get it to work correctly. Or maybe there's some better way to test setting a private variable.
Class
<?php
namespace PureChat\src\messages;
/**
* Message class for containing information about a message.
*/
class Message
{
/**
* Contains the message text.
* #var string
*/
private $messageText;
/**
* Sets the instance variable $messageText.
* #param string $text The text to assign.
*/
public function setText($text)
{
$this->messageText = $text;
}
}
PHPUnit Test
<?php
use PureChat\src\messages\Message;
class MessageTest extends \PHPUnit_Framework_TestCase
{
public function testMessageCanSetText()
{
$message = new MessageStub;
$message->setText('test-text');
$this->assertEquals(
$message->messageText, 'test-text');
}
}
class MessageStub extends Message
{
public $messageText;
}
When run, the test fails with "Failed asserting that 'test-text' matches expected null." My first thought was that maybe the stub class wasn't inheriting the setText method, so I tested that as well with method_exists, however the method does exist, so I'm at a loss.
Private properties are not inherited, so $messageText already is not inside the MessageStub class. And it cannot be set by the inherited method setText.
And then you are using assertEquals() arguments in the wrong order: The first one should be the value you expect, and the second one is the value you test. Flip the arguments - then the error message makes more sense, because currently the message says you expect NULL - but you expect the string 'test-text'.
And then we come to the topic of testing philosophy. A good unit test only checks the outside of an object, but should not care about the inner workings. If you set a value, the success of setting it should somehow be detectable from the outside. When you only have the very basic setter/getter combo, it is indeed very boring to test them, but that's what you should do: set a valid value, get it back, assert it is the same as before, and assert that no errors occurred (this is done automatically by PHPUnit because any PHP error or exception would make the test fail).
If there is no getter for that value - either there is no use in setting the value anyways because it is never used, or you can test it by testing the part that uses the value.
$message->setText('foo');
$message->saveText(); // uses value from setText()
If you want to test this, you'd probably call these two methods in one test. And you need to test that calling saveText alone will trigger an error. Or saves the default value.
Or you come to the conclusion that having TWO methods to do one thing is not a very good idea because testing them is not that easy, so your experience from testing may make you think about improving the API of that message object. You probably want to get rid of that setText method somehow.
Yes, using Reflection to get access to the private property is a way to test it. But now you are tightly binding your test to the internal construction of the object. If you rename the private property, your test breaks - but it shouldn't break because you haven't change the public interface.
You could use reflection.
$message = new Message;
$message->setText('test-text');
$property = (new \ReflectionObject($message))->getProperty('messageText');
$property->setAccessible(true);
$value = $property->getValue($message);
$property->setAccessible(false); // restore state
echo $value;
I'm new to Laravel and the concept of the IoC. I was following the great tutorials over a Nettuts (http://net.tutsplus.com/tutorials/php/testing-laravel-controllers/) and was able to successful test my controller. However I wanted to isolate the controller by mocking the database. As soon as I attempted to inject my mocked object into the IoC I get the following error:
Cannot modify header information - headers already sent by (output started at /Users/STRATTON/Dev/SafeHaven/vendor/phpunit/phpunit/PHPUnit/Util/Printer.php:172)
The line it's referring to outputs PHPUnit's buffer using the 'print' construct. Something is causing output to be sent before headers are set but I can't track down the problem.
I'm able to run all my tests successfully when the controller calls the real model and makes the database call. At the same time I'm able to mock the object successfully and exercise mock without error. But as soon as I attempt to inject the mocked object using App::instance() the error appears.
I've also tested this with PHPUnit's mocks and get the same results. Am I mocking the object properly? Do I have a problem with namespacing? Am I missing something that's outputting content?
Controller:
<?php namespace App\Controllers;
use App\Models\Repositories\ArticleRepositoryInterface;
class HomeController extends BaseController {
protected $articles;
public function __construct(ArticleRepositoryInterface $articles)
{
$this->articles = $articles;
}
public function index()
{
$articles = $this->articles->recent();
return \View::make('home.index')
->with('articles', $articles);
}
}
TestCase
<?php namespace Tests\Controllers;
class HomeControllerTest extends \TestCase {
public function testIndex()
{
$mocked = \Mockery::mock('App\\Models\\Repositories\\ArticleRepositoryInterface');
$mocked->shouldReceive('recent')->once()->andReturn('foo');
\App::instance('App\\Models\\Repositories\\ArticleRepositoryInterface', $mocked);
//$mocked->recent();
$this->call('GET', '/');
$this->assertResponseOk();
$this->assertViewHas('articles');
}
}
It actually a a bug on how exception is handled during running test case, this however has been fixed, just run composer update.
Answering my own question - The reason for the error is that some part of the code is causing a PHP error or an exception to be thrown.
In this case, the problem was an Exception thrown from the View. The View was expecting that the value returned by the method recent() was an Eloquent Collection (Illuminate\Database\Eloquent\Collection), or at least something that the View could iterate over.
THe HomeControllerTest::TestIndex method was mocking the object and when recent() was called it returned 'foo'. There's no way for the View to iterate over a string so it throws an exception. The two solutions are below, the later allowing the ability to test that the view received the correct object type.
$mocked->shouldReceive('recent')
->once()
->andReturn([]);
If you're having a similar issue, examine all the code being tested and make sure you're tests actually fulfill all the requirements/dependancies... or use TDD... something I should have done from the start and avoided this issue.
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.