How to reuse PHPUnit functions - laravel-4

I want to reuse some of my PHPUnit functions by calling them instead of repeating them in all unit tests, such as this for example:
public function testContent()
{
$this->assertNotEmpty($this->response, $this->message);
}
If I place it under tests/TestCase.php, it runs for all the unit tests.
Where would be the right place to put this or how is this usually done? Btw, I am using it on Laravel 4.

Apparently, your problem is not to re-use tests, but that your tests are beeing called when it's not expected.
So, have in your mind: any method with a name starting with "test" (testFoo, testBar) in an existing class will be considered as a test.
So if you have classes A, B and C like this
class A extends \PHPUnit_Framework_TestCase {
public function testFoo() {...}
public function testBar() {...}
}
class B extends A {
public function testBaz() {...}
}
class C extends A {
public function testQuz() {...}
}
you will have 8 tests: A::testFoo(), A::testBar(), B::testFoo(), B::testBar(), B::testBaz(), C::testFoo(), C::testBar(), C::testQuz().
It's probably is not what you was trying to make.
You may want to have testFoo and testBar only in classes B and C, not it A. In this case, you just have to declare A as an abstract class.
abstract class A extends \PHPUnit_Framework_TestCase {
public function testFoo() {...}
public function testBar() {...}
}
class B extends A {
public function testBaz() {...}
}
class C extends A {
public function testQuz() {...}
}
Now you have 6 tests: B::testFoo(), B::testBar(), B::testBaz(), C::testFoo(), C::testBar(), C::testQuz().
Maybe, it's what you need, maybe not. Maybe, you want to have testFoo() and testBar() only in some inherited classes, not all of them.
In this case, make assertions in you parent class instead of tests.
abstract class A extends \PHPUnit_Framework_TestCase {
public function assertFoo() { ... }
public function assertBar() { ... }
}
class B extends A {
public function testFoo() { $this->assertFoo(); ...}
public function testBaz() {...}
}
class C extends A {
public function testBar() { $this->assertBar(); ...}
public function testQuz() {...}
}
Now, you have only 4 tests: B::testFoo(), B::testBaz, C::testBar(), C::testQuz()

Make your own assertion according to this manual
Make something like
namespace Vendor\Library\Tests;
abstract class BaseTestCase extends \PHPUnit_Framework_TestCase
{
public function assertContentNotEmpty($response) {
$this->assertNotEmpty($response);
}
}
And then extend this class with your tests.
If this approach is not convenient for some reasons, you can make an assertion as a separate class.

Related

Laravel contextual binding to be more specific to methods rather then class only

I am trying to understand laravel bind.
let's say, I have UploadFileController.php
Route::post('/upload/images', 'UploadFilesController#uploadImage');
Route::post('/upload/pdf', 'UploadFilesController#uploadPdf');
then in the controller,
class UploadFilesController extends Controller
{
private $uploadServiceInterface;
public function __construct(UploadServiceInterface $uploadServiceInterface)
{
$this->uploadServiceInterface = $uploadServiceInterface;
}
public function uploadImage(Request $request)
{
$this->uploadServiceInterface->store();
}
public function uploadPdf()
{
$this->uploadServiceInterface->store();
}
}
Now, the uploadServiceProvider,
class UploadServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->when(UploadFilesController::class)
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
}
}
Now, I know "when" says that UploadFileController class with uploadService interface will give the imageUploadService but is it possible I make it more specific to function in uploadFileController class, like
$this->app->when(uploadFilesController::uploadImage())
->needs(UploadServiceInterface::class)
->give(ImagesUploadService::class);
then it takes to the imagesUploadService class same for pdf upload class.

bind abstract class service in provider laravel

Gives an error:
Target [MyVendor\ProductList\ProductServiceInterface] is not instantiable.
ProductServiceInterface
namespace MyVendor\ProductList;
interface ProductServiceInterface
{
public function productList();
public function getProductSpeed();
}
ProductColorService
namespace MyVendor\ProductList\Service;
abstract class ProductColorService implements \MyVendor\ProductList\ProductServiceInterface
{
public function productList()
{
$color = "black";
return $color;
}
}
** ProductSpeedService **
namespace MyVendor\ProductList\Service;
abstract class ProductSpeedService implements \MyVendor\ProductList\ProductServiceInterface {
public function getProductSpeed() {
$speed = 200;
return $speed;
}
}
Provider :
namespace MyVendor\ProductList;
use Illuminate\Support\ServiceProvider;
use MyVendor\ProductList\ProductServiceInterface;
use MyVendor\ProductList\Service\ProductColorService;
class ProductColorServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadRoutesFrom(__DIR__ . '/routes/color.php');
}
public function register()
{
$this->app->bind('MyVendor\ProductList\ProductServiceInterface','MyVendor\ProductList\Service\ProductColorService');
$this->app->bind('MyVendor\ProductList\ProductServiceInterface','MyVendor\ProductList\Service\ProductSpeedService');
}
}
Whats wrong in this code? Actually I need to override some functions in interface using service. ie each service should override one method.
namespace MyVendor\ProductList\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use MyVendor\ProductList\Models\Product;
use MyVendor\ProductList\ProductServiceInterface;
class ProductListController extends Controller
{
public function index(ProductServiceInterface $product_service)
{
$color = $product_service->productList();
$speed = $product_service->getProductSpeed();
dd($color," = ",$speed);
$product = Product::get();
return view('ProductList::product',compact('product'));
}
}
here productList() in one service and productSpeed() from another service
You can't instantiate abstract classes. The whole point of them is there can never be an instance of them, so if you bind your interface to your abstract class with a method, it simply can never be abstract. Abstract is for classes in inheritance structures you do not want to have the users to create new ones.
So there is no reason for the abstract, abstract is for something like this.
abstract class Vehicle {
protected $wheels;
public function getWheels() {
return $this->wheels;
}
}
class Car extends Vehicle {
protected $wheels = 4;
}
class Bike extends Vehicle {
protected $wheels = 2;
}
You can not make a vehicle as it is not a concrete implementation, as it is a parent class to help with methods shared across two classes. So short version, just remove the abstract keyword. If you don't know why you add it, it is not needed.

How to mock classes within command classes in Laravel

I am using Laravel 5.3. For a procedur I am using a command. The command class is calling a method of an another class. I wanted to unit test it with phpunit. Therefore I mocked up the class within the command class. When I run the test, then the actual method of class is running and not the mocked method. Bevor I have implemented the functinality of the command in a job. There I can call the mocked method without any problem.
The test class looks like this:
class CommandTest extends TestCase
{
public function setUp()
{
parent::setUp();
$this->api = $this->getMockBuilder('App\Services\APIRepository')
->setMethods(['getStatus'])
->getMock();
}
/** #test */
public function test_api()
{
...
$this->api->expects($this->any())
->method('getStatus')
->will($this->returnValue($api_response));
\Artisan::call('myapp:tracker',[]);
...
}
}
class Command extends Command
{
protected $signature = 'myapp:tracker';
private $api;
public function __construct(APIRepository $api)
{
$this->api = $api;
}
public function handle()
{
...
$status = $this->api->getStatus(...);
var_dump($status);
...
}
}
The output of var_dump($status) is: NULL
Do I need a special method for mocking a class within a command class?
Thanks a lot in advanced!

Laravel dependency injection into custom non-controller class fails in PHPUnit

all.
For a Laravel project I'm working on, I've started to use Dependency Injection in order to mock classes in my tests. However, I've found that if I try to inject into a custom class with no explicit parent, two things are true:
The dependency injection works correctly when running the application
The injection fails when running tests in PHPUnit
Here is some sample code similar to what I'm using:
DemoController
// The controller we're testing
class DemoController extends Controller
{
// The injection and constructor
private $helpLayer1;
public function __construct(HelpLayer1 $helpLayer1)
{
$this->helpLayer1 = $helpLayer1;
}
...
// The test function I call
public function testDeps()
{
$this->helpLayer1->testLayer1();
}
}
HelperLayer1
// Our first helper class
class HelperLayer1
{
private $helpLayer2;
public function __construct(HelpLayer2 $helpLayer2)
{
$this->helpLayer2 = $helpLayer2;
}
...
// The testing function
public function testLayer1()
{
// When called via route, this dumps the actual object
// When called via test, this returns null
dd($this->helperLayer2);
}
}
Helper1ServiceProvider
class Helper1ServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('HelperLayer1', function()
{
return new HelperLayer1(App::make('HelperLayer2'));
});
}
[OR]
public function register()
{
$this->app->bind('HelperLayer1', 'HelperLayer1');
}
}
Helper2ServiceProvider
class Helper2ServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('HelperLayer2', 'HelperLayer2');
}
}
I'm relatively new to using DI, so I'm not entirely sure that this set-up is correct, but I'm at a loss.
Any help would be greatly appreciated! Thank you!

Session class not available in setUpBeforeClass

When my very first unit test class is run, why is the Session class not available in setUpBeforeClass? After the first unit test class has finished, the session class is available in setUpBeforeClass.
Is there something I can do to make sure that Session is available in my first unit test?
<?php
class AATest extends TestCase
{
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
\Session::put('tenantId',100); // <-- this fails
\Session::put('userId',1100);
}
public function setUp()
{
parent::setUp();
\Session::put('tenantId',100); // <-- if removed from before class, this works.
\Session::put('userId',1100);
}
public function test1()
{
$tenantId = \Session::get('tenantId');
$userId = \Session::get('userId');
$this->assertEquals(100,$tenantId);
$this->assertEquals(1100,$userId);
}
}

Resources