Have setup method run only once - php

I have:
1. IntegrationTestCase extends TestCase
2. UnitTestCase extends TestCase
3. AcceptanceTestCase extends TestCase
In these I have quite a lot of non-static methods which are used in a lot of tests. All of my Test classes extend one of these 3 classes.
Now in a lot of Test classes I have a setUp method which preps the data and services needed and assigns them to class variables:
class SomeTestClass extends IntegrationTestCase
{
private $foo;
public function setUp()
{
parent::setUp();
$bar = $this->createBar(...);
$this->foo = new Foo($bar);
}
public function testA() { $this->foo...; }
public function testB() { $this->foo...; }
}
Problem is setUp is ran for each test defeating what I wanted to do and if what setUp method does takes a long time this is multiplied by the number of test methods.
Using public function __construct(...) { parent::__construct(..); ... } creates a problem because now lower level methods and classes from Laravel are not available.

For the next person running into this issue:
I had the problem that I wanted to migrate the database before running my tests but I didn't want the database to be migrated after each single test because the execution time would be way too high.
The solution for me was using a static property to check if the database was already migrated:
class SolutionTest extends TestCase
{
protected static $wasSetup = false;
protected function setUp()
{
parent::setUp();
if ( ! static::$wasSetup) {
$this->artisan('doctrine:schema:drop', [
'--force' => true
]);
$this->artisan('doctrine:schema:create');
static::$wasSetup = true;
}
}
}

Solution given by Saman Hosseini and similar didn't workout for me. Using the static property to flag getting reset for the next test class.
To overcome this I've wrote separate test class to test the test database connection & initialize the test database for once & made sure this runs before all the other tests
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;
/**
* #runTestsInSeparateProcesses
*/
class DatabaseConnectionTest extends TestCase
{
/**
* Test the database connection
*
* #return void
*/
public function testDatabaseConnection()
{
$pdo = DB::connection()->getPdo();
$this->assertNotNull($pdo);
}
/**
* Initialize the test database for once
*
* #return void
*/
public function testInititializeTestDatabase()
{
Artisan::call('migrate:fresh');
Artisan::call('db:seed');
}
}

I recommend using the template methods called setUpBeforeClass and tearDownAfterClass
The setUpBeforeClass() method is called before the first test is executed and the tearDownAfterClass() method is called after last test is executed.
We use these two methods to share settings with all the tests.
For example, it is wise to get the database connection once in the setUpBeforeClass() method then get connection multiple times in the setUp() method.
And likewise, it is wise to close the database connection only once in the tearDownAfterClass() method then close the database connection after every test in the tearDown() method.

I am not sure what issues you see for setUpBeforeClass is static except for the one mentioned by Mark Baker. I assume you do know what you are doing, though. Here is a sample of possible usage.
class BeforeAllTest extends PHPUnit_Framework_TestCase
{
private static $staticService;
private $service; // just to use $this is tests
public static function setUpBeforeClass() {
self::createService();
}
public static function createService(){
self::$staticService = 'some service';
}
/**
* just to use $this is tests
*/
public function setUp(){
$this->service = self::$staticService;
}
public function testService(){
$this->assertSame('some service', $this->service);
}
}
UPDATE: just somewhat similar approach you can see at https://phpunit.de/manual/current/en/database.html (search for 'Tip: Use your own Abstract Database TestCase'). I am sure you are already using it since you are doing intensive db testing. But nobody restricts this way for db-issues only.
UPDATE2: well, I guess you would have to use smth like self::createService instead of $this->createService (I've updated the code above).

Related

Tell phpunit to call public instead of private

My Question is. I have a class i want to test (myClass). In myClass there is a function wich calls a private function thats also in the myClass.
I know i can't test private functions. Is it possible to tell phpunit to call another function instead of the private?
Example
$this->testclass is now the class i want to test
$this->testclass = new \stdClass();
$this->testclass->mock = $this->getMockBuilder('myClass')->getMock();
Outside my testcase i have created a fake class.
$this->mockextended = new \stdClass();
$this->mockextended->mock = new MOCKEXTENDEDCLASSES();
in the $this->mockextended i have a public function.
the function i want to test
public function TestMe(){
$this->somePrivateFunctioniHate(); <==== this is the pain in my ass
}
and the private function
private function somePrivateFunctioniHate(){
//come code
}
What i want to do is. the function TestMe is calling a private function.
Is it possible to tell phpunit to override the private function and call another function thats inside $this->mockextended;
I have tried it like this.
$this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction()
only this gives me a nice error. I did this before and it worked. Called it like this
EDIT
For people who don't understand my question.
I have another function that calls another class. I din't want to have another class in my test so i created a fake Class outside my testcase. Inserted the same functions as the class the function wants to include. Did it like this
$this->testclass->chunks = new \stdClass();
//MOCKchunckTpl is the fake class outside my testcase
$this->testclass->chunks->config = new MOCKchunkTpl();
This works. Whenever a function wants to call $this->testclass->chunks->config->Somefunction(); it will be redirected to my fake class.
BUT when i try to do the same with a function thats calling a private function. Like $this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction() it gives a nice error
Fatal error: Can't use method return value in write context in
Short answer: No, there isn't. There is no way for PHPUnit to manipulate private methods.
Mocks are for faking the behavior of classes, which depend on the class you want to test. If you need to overwrite a private method, there is something wrong in your architecture. Private methods should be tested by simple testing the public methods in which they are used. If you need to test it separately, declare it public.
EDIT: Here is an example how you'd test a simple code using a private method or putting this private method in another class:
1. Private method
class MyClass {
public function myMethod() {
return $this->myPrivateMethod();
}
private function myPrivateMethod() {
return 2;
}
}
And the test class:
class MyClassTest extends \PHPUnit_Framework_TestCase {
public function testMyMethod() {
$myClass = new MyClass();
// don't mind the private method, just test if the public method is working
$this->assertEquals(2, $myClass->myMethod());
}
}
1. Second class
class MyClass {
public $dependentClass;
public function myMethod() {
return $this->dependentClass->dependentMethod();
}
}
And the dependent class:
class DependentClass {
public function dependentMethod() {
return 38943;
}
}
Testing MyClass with the DependentClass:
class MyClassTest extends \PHPUnit_Framework_TestCase {
public function testMyMethod() {
$dependentMock = $this->getMockBuilder("DependentClass")->getMock();
$dependentMock->expects($this->any())
->method("dependentMethod")
->willReturn($this->returnValue(2));
$myClass = new MyClass();
$myClass->dependentClass = $dependentMock;
$this->assertEquals(2, $myClass->myMethod());
}
Although we defined a whole other return in DependentClass, the test will still pass, because we mocked it and are able to define every behavior we'd expect DependentClass to have.
But to cleanly test the project, we need to define another test for DependentClass as well to test, if this class is working. This test should fail if it is not working anymore, not the test for MyClass.

PHP Unit: Create common object to work with

I'm writing PHP Unit tests for a class, which make some curl requests. At the moment every test starts with my class instance initiation and login directive and ends with logout directive, e.g.
public function testSomeMethod(){
$a = new myClass();
$a->login();
....
$a->logout();
$this->assertTrue($smth);
I want to create one common object $a = new myClass(), call login method before all test and logout method after all tests. How can I do that?
In accordion with the PHPUnit documentation here you can use the following hook method:
The setUp() and tearDown() template methods are run once for each test
method (and on fresh instances) of the test case class.
Also
In addition, the setUpBeforeClass() and tearDownAfterClass() template
methods are called before the first test of the test case class is run
and after the last test of the test case class is run, respectively.
In your case you can define the login class as class member and instantiate (login) in the setUpBeforeClass() method and do the logout in the tearDownAfterClass()
EDIT: EXAMPLE
Consider the following class:
namespace Acme\DemoBundle\Service;
class MyService {
public function login()
{
echo 'login called'.PHP_EOL;
}
public function logout()
{
echo 'logout called'.PHP_EOL;
}
public function doService($name)
{
echo $name.PHP_EOL;
return $name;
}
}
This test case:
use Acme\DemoBundle\Service\MyService;
class MyServiceTest extends \PHPUnit_Framework_TestCase {
/**
* #var \Acme\DemoBundle\Service\MyService
*/
protected static $client;
public static function setUpBeforeClass()
{
self::$client = new MyService();
self::$client->login();
}
public function testSomeMethod1()
{
$value = self::$client->doService("test1");
$this->assertEquals("test1",$value);
}
public function testSomeMethod2()
{
$value = self::$client->doService("test2");
$this->assertEquals("test2",$value);
}
public static function tearDownAfterClass()
{
self::$client->logout();
}
}
Dump the following output:
login called .test1 .test2 logout called
Time: 49 ms, Memory: 6.00Mb
OK (2 tests, 2 assertions)
hope this help
Creating reusable / common object at class level ( to be use in methods/functions) answer by #Matteo was helpful, Here is my implementation
no need for multiple inheritance , or __construct() constructor, I spent a lot of time on that ( specially coming from java background)
<?php
namespace Tests\Unit;
use Tests\TestCase;
use App\Services\HelperService;
class HelperServiceTest extends TestCase
{
//Object that will be reused in function()'s of this HelperServiceTest class itself
protected static $HelperServiceObj;
//this is the magic function
public static function setUpBeforeClass()
{
self::$HelperServiceObj = new HelperService();
}
public function testOneHelperServiceToBeTrue()
{
$this->assertTrue(self::$HelperServiceObj->getValue());
}
public function testTwoHelperServiceToBeTrue()
{
$this->assertTrue(self::$HelperServiceObj->getValueTwo());
}
}
Refer official docs setUp() , setUpBeforeClass() , tearDown() for magic function like setUpBeforeClass()
Sample implementation of getValue() function in HelperServiceTest class
<?php
namespace App\Services;
class HelperServiceTest
{
function getValue(){
return true;
}
function getValueTwo(){
return true;
}
}

Close a test using Selenium Webdriver PHP

Here's how I write my tests:
A class with private methods and a single public method which runs all my others private methods.
class MyTest extends PHPUnit_Framework_TestCase
{
private function firstScenario() {
$this->navigation = new Navigation($this->webDriver);
$this->navigation->goToPointA();
//...
}
private function secondScenario() {
$this->navigation = new Navigation($this->webDriver);
$this->navigation->goToPointA();
//...
}
public function testRun() {
//...
$this->firstScenario();
$this->secondScenario();
//...
}
I have in other classes some generic methods, whose one named Navigation.php. In this class, I have all my methods which enable me to go to a specific point of my application.
All I want to do is, according to a condition, to close (or quit, or dispose, or whatever you want) my test, properly, without returning an error. I tried quit(), close() and dispose() but maybe I use its wrong.
You should probably add quit() to your tear down. Depending on how you are invoking driver it would be something like:
protected function tearDown() {
if ($this->driver) {
$this->driver->quit();
}
}

phpUnit: Pass argument into tearDownAfterClass from a test

I'm using phpUnit. Is it possible to pass a result from another test to the tearDownAfterClass. I know it's possible to use #depends to make other tests depend on a test for data. Is it possible to pass that data to tearDownAfterClass afterwards somehow.
#depends doesn't seem to work for tearDownAfterClass.
You can use a static property holding the "params"/data for the tearDownAfterClass. The static properties are not overwritten in subsequent tests unless you do so (you can learn more about static keyword here http://php.net/manual/en/language.oop5.static.php).
Here is an example in which it uses the database.
From https://phpunit.de/manual/current/en/fixtures.html:
<?php
class DatabaseTest extends PHPUnit_Framework_TestCase
{
protected static $dbh;
public static function setUpBeforeClass()
{
self::$dbh = new PDO('sqlite::memory:');
}
public static function tearDownAfterClass()
{
self::$dbh = NULL;
}
}
?>
Wish it helps!

Injecting DB class into the __constructor variable inside an Abstract Class

Unable to inject Laravel's DB class into an abstract class located in another namespace folder.
Getting Error "Call to undefined method Illuminate\Support\Facades\DB::table()"
-Check:Working-
FrontController.php
<?php
use MyProject\MainPages\Front;
class indexController extends \BaseController {
/**
* #var Front
*/
private $Front;
/**
* #param ProductRepository $productRepo
*/
function __construct(Front $Front)
{
//Test
//$this->Front = $Front->goSetup();
}
}
-Check:Working-
Front.php
<?php namespace MyProject\MainPages;
use MyProject\MainPages\NavigationSkeleton;
class Front extends NavigationBluPrint {
/**
* Begins the process, Step 1
*/
protected function goSetup() {
// $this->DB->table() etc
}
}
-Not Working-
NavigationBluPrint.php
<?php namespace MyProject\MainPages;
use \DB;
abstract class NavigationBluPrint {
/**
* #var DB Laravel Database connection
*/
protected $dB;
public function __construct(DB $dB)
{
// SetDB so when extended it's already set for extended classes
$this->dB = $dB;
// Test below
$x = $this->dB->table('products')->get(); //Error: Call to undefined method Illuminate\Support\Facades\DB::table()
echo '<pre>';
print_r($x);
echo '<pre>';
}
}
If I need to do something with App:: to make this work, I dont understand how it's done. Thank you
Solution Found:In case someone else runs into the same problem.
In abstract class "NavigationBluPrint.php"
I replaced \DB; with=> use \Illuminate\Database\DatabaseManager as DB;
It seems to fix the problem, although I'm not sure whether its instantiating a new DB from start or using the same one. If former then it kind of defeats the purpose.
You're type hinting the facade for the DB class, not the DB class itself.
It's false the idea of using static method, via object and it is impossible.
you should create repository for your database operation then you can inject them greatly.
directions to create Eloquent repository or DB repository :
Here I found out a great article to do this.

Categories