How would i unit test an interface such as this following simple example:
interface My_App_My_Interface
{
/**
* #return int
*/
public function getInteger();
/**
* #return string
*/
public function getString();
}
also how would this be organised in my applications test directory:
tests > My > App > My > InterfaceTest ??
you don't test interfaces. you test implementation. interfaces should be checked (by human) if they provide all required functionality
As piotrek said, you will never test interfaces as they are just a contract, there is no code in there.
For example, with atoum testing framework you could write for a class that implements your interface.
namespace mageekguy\atoum\tests;
class TestMyInterfaceImplementation extends atoum\test{
public function test__construct(){
$object = new MyObject();
$this->object($object)->instanceof('MyInterface');
}
public function test_getInteger(){
$object = new MyObject();
$this->integer($object->getInteger);
}
}
As an interface just provides abstract methods, they just can't be instanciated so no test can be written.
Related
I want to mock a method foo in a class but leave method bar as it is:
<?php
class MyClass
{
protected $dep1;
protected $dep2;
protected $dep3;
protected $dep4;
/**
* Test constructor.
* #param $dep1
* #param $dep2
* #param $dep3
* #param $dep4
*/
public function __construct($dep1, $dep2, $dep3, $dep4)
{
$this->dep1 = $dep1;
$this->dep2 = $dep2;
$this->dep3 = $dep3;
$this->dep4 = $dep4;
parent::__construct();
}
public function foo()
{
return "foo";
}
public function bar()
{
return "bar";
}
}
However, MyClass is instantiated via a factory which retrieves the dependencies ($dep1, $dep2, ...) and inject them directly in to the constructor of MyClass.
So I want to use that Factory and instantiate a MyClass-object (otherwise the complex instantiation has to be coded in the test case also).
In short I want to know if there is another solution than:
class TestMyClass extends \PHPUnit\Framework\TestCase {
public function setUp()
{
// complicated way to retrieve $dep1 to $dep4
$mock = $this->getMockBuilder(MyClass::class)->setMethods(['foo'])->setConstructorArgs([$dep1, $dep2, $dep3, $dep4])->getMock();
$mock->expects($this->any())->method('foo')->willReturn(false);
}
}
Is it possible to somehow create proxy to an already created instance of MyClass, which just overrides the foo method? Is there another way (without runkit pecl extension) to mock an method of an existing/instantiated object?
I know PHPUnit has some Proxy-related methods, but I couldn't find any documentation / example of usage of them, so I am not sure if they even could be used to solve my problem.
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).
I am working with Symfony2 and trying to write some PHPUnit test for one of my classes.
This is what I have done so far following Symfony2 testing Docs i created a folder under Tests directory with a file myClassTest.php ini it:
<?php
namespace Test\TestBundle\Tests\Template;
use Test\TestBundle\Dto\Template\myTemplate;
class myTemplateTest extends \PHPUnit_Framework_TestCase
{
public function testMyMethod()
{
$test = new myTemplate();
}
}
This is myTemplate:
<?php
namespace Test\TestBundle\Dto\Template;
use Test\TestBundle\Doctrine\DatabaseRepository;
use Test\TestBundle\Validation\ValidationClass;
class myTemplate
{
/**
* #var ValidationClass
*/
private $validate;
/**
* #var DatabaseRepository
*/
private $db;
/**
* #param ValidationClass $validation
* #param DatabaseRepository $databaseRepository
*/
public function __construct(
ValidationClass $validation,
DatabaseRepository $databaseRepository
) {
$this->validate = $validation;
$this->db = $databaseRepository;
}
}
Errors:
Argument 1 passed to Test\TestBundle\Dto\Template\myTemplate::__construct()
must be an instance of Test\TestBundle\Validation\ValidationClass, string given,
called in Dev/project/src/Test/TestBundle/Tests/Template/myTemplateTest.php
More Errors:
This error points to the injected service in the construct $validation
Dev/project/src/Test/TestBundle/Dto/Template/myTemplate.php:42
This error corresponds to the instantiate class of myTemplate class
Dev/project/src/Test/TestBundle/Tests/Dto/Template/myTemplateTest.php:15
I understand the errors well i think I do but i have no idea how to fix it and these errors are shown when i run phpunit test.
For testing with PHPUnit, you should use Mocks and Stubs for imitation logic in your depends classes.
Before initialize myTemplate in test case, you should create a mock of this objects, or create original objects.
$validationMock = $this->getMock('ValidationClass');
$dbRepositoryMock = $this->getMock('DatabaseRepository');
$myTemplate = new myTemplate($validationMock, $dbRepositoryMock);
And after you can use invocation system for control called methods.
For more information, please visit PHPUnit site:
https://phpunit.de/manual/current/en/test-doubles.html
This question might sound obvious and might be stupid as well. But I am trying to figure out why do I need to use interfaces? I think I can handle most of the things which interfaces do using classes then what's the point of using them? It's true that I might end up in problems if I don't interfaces but I am trying to figure out what problems are caused by not using interfaces?
One use of interfaces is that they allow us to define behaviors and put restrictions on of classes which implement them.
Another use is that interface work as types and I can use interfaces for type hinting as shown below.
//Java example
public interface IPaintable{
void Paint(System.Drawing.Color color);
}
public void Paint(IPaintable item, System.Drawing.Color color){
item.Paint(color);
}
But are there any other use of interfaces in PHP?
I.e. What advantages do I get by using interfaces in the code below.
//Non interface implementation
<?php
class DBPersonProvider
{
public function getPerson($givenName, $familyName)
{
/* go to the database, get the person... */
$person = new Person();
$person->setPrefix("Mr.");
$person->setGivenName("John");
return $person;
}
}
/* I need to get person data... */
$provider = new DBPersonProvider();
$person = $provider->getPerson("John", "Doe");
echo($person->getPrefix());
echo($person->getGivenName());
?>
//Implementation with interface
<?php
interface PersonProvider
{
public function getPerson($givenName, $familyName);
}
class DBPersonProvider implements PersonProvider
{
public function getPerson($givenName, $familyName)
{
/* pretend to go to the database, get the person... */
$person = new Person();
$person->setPrefix("Mr.");
$person->setGivenName("John");
return $person;
}
}
/* I need to get person data... */
$provider = new DBPersonProvider();
$person = $provider->getPerson("John", "Doe");
echo($person->getPrefix());
echo($person->getGivenName());
?>
I write a nice library that interacts with the database. And I use MySQL. When you purchase my library, you know it's MySQL based but you roll with SQL Server. I was considerate enough to create interfaces for the Database access. And I provided an implementation for MySQL. Now you can implement your own SQL Server wrapper around my database access interface, and then use it as a __construct() argument for the classes in the library you will use to change move storage to SQL Server.
Interfaces are very useful for library / reusable code writers like me :) They are code contracts that have to be obeyed. You know that any class that implements them WILL have a set of functions exactly as the Interface declared them. And you can also statically type them in function arguments like function(MyInterface $Object) which enforces, at PHP compiler level, that $Object must be implementing MyInterface.
PS: Abstract classes are good enough for the rest of self-written code consuming developers...
UPDATE:
/**
* Database Access functionality blueprint.
*/
interface IDatabaseAccess {
public function Connect();
public function Query();
public function Fetch();
}
/**
* Database Access functionality implementation for MySQL.
*/
class MySqlDatabaseAccess implements IDatabaseAccess {
public function Query(){
// do mysql stuff
}
public function Fetch(){
// do mysql stuff
}
}
/**
* Database Access functionality implementation for SQLServer.
*/
class SqlServerDatabaseAccess implements IDatabaseAccess {
public function Query(){
// do sqlserver stuff
}
public function Fetch(){
// do sqlserver stuff
}
}
/**
* Database Access consumer that's database system agnostic.
*/
class DatabaseAccessConsumer {
protected $_Provider = null;
public function __construct(IDatabaseAccess $Provider){
$this->_Provider = $Provider;
$this->_Provider->Connect();
}
public function Query(){
return $this->_Provider->Query();
}
public function Fetch(){
return $this->_Provider->Fetch();
}
}
^ code that should speak for itself.
Interfaces actually provide less features than abstract classes (you cannot implement anything).
But they resolve the problem of multiple inheritance. Most modern language do not allow a class to derive more than one class. By using an interface, which does not implement any method, you are sure there is no ambiguity when you invoke a method from the interface (because there is no implementation).
Example (syntactically not valid):
class A {
public foo() {
echo 'I am A and I foo';
};
public
}
class B {
public foo() {
echo 'I am B and I foo';
}
}
class C extends A, B { // invalid
public bar() {
foo(); // which one? A's or B's?
}
}
Second example:
class A {
public foo() {
echo 'I am A and I foo';
};
}
interface iB {
public foo();
public bar();
}
interface iC {
public foo();
public qux();
}
class D extends A implements iB, iC {
public bar() {
foo(); // no ambiguity, this is A::foo(), even if the method is also declared in the interfaces
}
public qux() {}
}
Interfaces are just blueprints of classes - they are ways of saying "If you are going to be doing something with this type of class, it must have this and do this." It allows you to control - to an extent - what another class will have/do at a minimum for a given situation. Not every situation calls for an iterface. Interfaces are best used in situations when you need to have some control over the basic code of certain classes but you may not be the one writing them. If you know that the extended classes will have x properties and y methods, then you can do basic future class support.
I'm currently working on an open source bundle for Symfony2, and really want it to be the dogs nadgers in terms of unit test coverage and general reliability, however I've run into a snag due to my lack of PHPUnit knowledge (or a complex scenario, who knows)..
At present, I have a Mailer class, for handling individual mail scenarios. It looks a bit like this:
<?php
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\Routing\RouterInterface;
class Mailer
{
protected $mailer;
protected $router;
protected $templating;
protected $parameters;
public function __construct($mailer, RouterInterface $router, EngineInterface $templating, array $parameters)
{
$this->mailer = $mailer;
$this->router = $router;
$this->templating = $templating;
$this->parameters = $parameters;
}
}
Simple enough, got some Symfony2 interface gubbins in there to handle different routing and templating systems, happy happy joy joy.
Here's the initial test I tried setting up for the above:
<?php
use My\Bundle\Mailer\Mailer
class MailerTest extends \PHPUnit_Framework_TestCase
{
public function testConstructMailer
{
$systemMailer = $this->getSystemMailer();
$router = $this->getRouter();
$templatingEngine = $this->getTemplatingEngine();
$mailer = new Mailer($systemMailer, $router, $templatingEngine, array());
}
protected function getSystemMailer()
{
$this->getMock('SystemMailer', array('send');
}
protected function getRouter()
{
$this->getMock('RouterInterface', array('generate');
}
protected function getTemplatingEngine()
{
$this->getMock('RouterInterface', array('render');
}
}
The problem here is that my mock objects do not implement Symfony\Bundle\FrameworkBundle\Templating\EngineInterface and Symfony\Component\Routing\RouterInterface, so I can't use any mock objects that I create myself. One method I have tried is creating an abstract class which implements the correct interface on the test page, however the getMockForAbstractClass fails, stating it can't find the class...
When mocking you need to use the full qualified class path as the mock functionality is not taking the namespace of the calling code or any "use" statements into consideration.
Try
->getMock('\\Symfony\\Component\\Routing\\RouterInterface');
and leave out the second parameter. Usually specifying the methods does a lot more worse than good.
Only if you want all the other methods to work like before than you should need the second parameter.
Example
<?php
namespace bar;
class MyClass {}
namespace foo;
use \bar\MyClass;
class MockingTest extends \PHPUnit_Framework_TestCase {
public function testMock() {
var_dump($this->getMock('MyClass') instanceOf MyClass);
var_dump($this->getMock('\\bar\\MyClass') instanceOf MyClass);
}
}
Produces:
/phpunit.sh --debug fiddleTestThree.php
PHPUnit #package_version# by Sebastian Bergmann.
Starting test 'foo\MockingTest::testMock'.
.bool(false)
bool(true)