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();
});
}
}
}
Related
I am desperately trying to unit test a module for a shopsystem. That shop system uses static methods which I have to call in my functions I want to test.
public function toTest() {
$value = \Context::getData();
return $value;
}
Now how can I unit test that function while mocking this static call? I tried using AspectMock but that does not work because it apparently needs access to the original \Context class which is not available since it's an external system. I also tried using class_alias to create my own Context class but that does not work either because I need different Context output depending on which function I am testing. And setting class_alias multiple times for different tests does not work because the same class can't be declared multiple times and #runTestsInSeparateProcesses did not have the expected effect.
Edit: None of the duplicates provided a viable solution to my situation, so I don't think this is a duplicate. With no access to the shopsystem code and especially with hard to maintain code like that, PHP does not make it easy to unit test this. Also the solution I found should help others with similar settings.
I could solve my issue with the Mockery library. I tried out a few but nothing worked. With Mockery everything seems possible now. This link really helped: https://robertbasic.com/blog/mocking-hard-dependencies-with-mockery/
You can easily mock static calls to classes that don't belong to you:
public function methodToTest() {
return \Context::getData();
}
public function testMethodToTest() {
m::mock('alias:\Context')
->shouldReceive('getData')
->andReturn('foo');
}
And even instantiations for classes you don't have access to:
public function methodToTest() {
$obj = new \Category(5);
return $obj->id;
}
public function testMethodToTest() {
m::mock('overload:\Category')
->shouldReceive('__construct')
->with(5)
->andSet('id', 5);
}
But you have to keep in mind that you need the two phpunit annotations at the beginning of the class:
* #runTestsInSeparateProcesses
* #preserveGlobalState disabled
I'm coding functional tests with sqlite in memory for faster results.
Everything seems ok, but I have several tables that needs to be filled so the tests works. They are small tables, and almost never change, so I would like to seed them once on the beginning of the phpunit command only.
Is it posible???
The only thing I fought is adding: Artisan::call('db:seed'); to createApplication() but this will seed once for every tests, and I don't need it..
Any Idea how should I do it?
You can use environment variable for refreshing database whenever you want. I don't know if it's the best way but it works for me.
Add variable to .env file
DB_REFRESH=true
and change CeatesApplication.php trait method:
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
if(getenv('DB_REFRESH') === 'true') {
\Artisan::call('migrate:refresh');
\Artisan::call('db:seed');
putenv('DB_REFRESH=false');
}
return $app;
}
and then try in ExampleTest.php
public function testBasicTest()
{
$this->assertTrue(true);
}
public function testChangeDatabase()
{
//if database changes here set variable to true
//and it will be refreshed before the next test
putenv("DB_REFRESH=true");
}
public function testRefresh()
{
//you have fresh database here
}
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 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.