how to fix undefined method errors in Laravel 7.x phpunit? - unit-testing

I am experiencing strange errors. Like all of the common functions I saw online does are undefined in my phpunit..
I ran the test like this
./vendor/bin/phpunit
my code is like this
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class AppTest extends TestCase
{
use DatabaseMigrations;
use WithoutMiddleware;
/** #test */
public function test_can_push_data() {
$paramData = [
'param1' => 'value1',
'param2' => 'value2',
];
$response = $this->json('POST', route('app.push'), $paramData);
$response->assertStatus(200);
}
}
I am getting this error
1) Tests\Unit\AppTest::test_can_push_data
Error: Call to undefined method Tests\Unit\AppTest::json()
I also noticed that am getting errors for other functions, I don't know why
$this->post()
$this->get()
Any ideas what's going on?, most of the tutorials I saw online are using these common methods, and these are throwing errors in my code ..why?

You are extending the wrong TestCase class. PHPUnit's TestCase class does not have those methods. You are looking for the Illuminate\Foundation\Testing\TestCase class. This will allow your tests to use the methods per the documentation:
namespace Tests\Unit;
use Illuminate\Foundation\Testing\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class AppTest extends TestCase
...
It is worth noting, that it is ususally useful to create your own TestCase class, to provide common custom functionality. It is usually located at Tests\TestCase

Related

Using a type as a value in typescript

I'm using inject-loader to mock dependencies for a Typescript project being unit tested. The service I'm testing has an import line like this:
import pnp, { SearchQuery, Sort, SortDirection, CamlQuery } from "sp-pnp-js";
For my test, I want to mock several of the functions on pnp, but keep the classes intact. In my unit test file, I've included this import:
import { SearchQuery, Sort, SortDirection, CamlQuery } from "sp-pnp-js";
Which gives my test access to the necessary classes. I've declared a mock service object:
// mock services
const mockPnp = {
default: { ... }
};
Which I'm wiring into my target class instance:
Service = require("inject!./sharepointservice")({
"sp-pnp-js": mockPnp
}).Service;
And everything works, so long as I don't run any code that references those classes (ie. SearchQuery). To get that to work, I tried adding it to the mock:
// mock services
const mockPnp = {
default: { ... },
SearchQuery: SearchQuery
};
However, I get a 'SearchQuery' only refers to a type, but is being used as a value here error.
I've tried casting to any (same error), tricks with modules and exports, with no luck. I'm supposed to be able to write any Javascript with Typescript, and this would work trivially in Javascript - what am I missing here?
According to the definition file SearchQuery is an interface, which means that you can not treat it as a value (as the error message says).
Typescript interfaces aren't being compiled into the js output, and you can not use them at runtime.
Technically, since its just for type safety, I can do this
t: MyInterface = {};

ZF2 Mock crashes on undefined method

I'm following this tutorial for unit testing on ZF2. I'm familiar with unit testing, so I pretty much understand what's going on.
I'm getting a PHP Fatal error: Call to undefined method Mock_AlbumTable_9fb22412::fetchAll() in [my controller's route here].
If I'm following correctly, the controller calls fetchAll on my mock object. The weird part is why is it undefined, if I declared it in the mock expectations.
My test code is exactly the same on the link provided, (Literally copy/pasted), and my AlbumTable class is also from the tutorial:
<?php
namespace Album\Model;
use Zend\Db\TableGateway\TableGateway;
class AlbumTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
// ... more code ...
}
What am I missing here?
Edit: visiting said controller's route from the web browser works, so it's not an issue with the AlbumTable class, at the very least.
You miss this line:
$albumTableMock=$this->getMockBuilder('Album\Model\AlbumTable')
->disableOriginalConstructor()
->setMethods(array('fetchAll')) // <- you miss this line
->getMock();

Extending PHPUnit_Framework_TestCase while using dataProviders

I'm fairly new to using PHPUnit and I'm trying to use it more effectively by using data providers. I can get data providers to work when writing a normal test case, however I find that I'm rewriting my setup code for across several testcases. So I'm trying to extend PHPUnit_Framework_TestCase with a BaseTestCase class that does all of my common setup. This works if I run simple test in a test case that extends my BaseTestCase class. However I can't seem to use #dataProvider when extending my BaseTestCase class.
So my setup is:
class BaseTestCase extends PHPUnit_Framework_TestCase{
public static function setUpBeforeClass(){
//do setup
//this is getting called and it works
}
}
class myTest extends BaseTestCase{
public function myBasicTest(){
//this works
$this->assertEquals(2, 1+1);
}
public function myProvider(){
return [
[1,1,2],
[1,2,3],
[1,4,5],
]
}
/**
* #dataProvider myProvider
*/
public function testMyProvider($a, $b, $result){
//this doesn't work, the provider never gets called
//this would normally work if I extended PHPUnit_Framework_TestCase
$this->assertEquals($result, $a+$b);
}
}
I know the providers get ran before any of the setup does so I'm wondering if PHPUnit doesn't know that the provider exists because of the inheritance. Either way, does anyone know if what I'm trying to do is possible this way or does PHPUnit have another way of accommodating these types of situations?
Thanks for your help,
Jordan
Your test function does not begin with the word 'test'.
public function test_myProviderTest($a, $b, $result){
This is actually a non issue. I had an incorrect constructor setup in my test file. A very frustrating oversight.

CakePHP test behaviour with mapped method

Whilst creating an OwnableBehavior I decided to use the $mapMethods property that is available. It is to map any method called isOwnedByXXX() to isOwnedBy() (The link for the documentation on this is here)
Here is my OwnableBehavior code:
class OwnableBehavior extends Model Behavior {
public $mapMethods = array('/isOwnedBy(\w+)/' => 'isOwnedBy');
public function isOwnedBy(Model $model, $type, $id, Model $userModel, $userId) {
// Method is currently empty
}
}
Here is the TestCase code:
class OwnableBehaviorTest extends CakeTestCase {
public function testIsOwned() {
$TestModel = new Avatar();
$TestModel->Behaviors->attach('Ownable');
$result = $TestModel->Behaviors->Ownable->isOwnedByUser(
$TestModel, 1, new User(), 1);
$this->assertTrue($result);
}
}
When I run the test I get this error:
Call to undefined method OwnableBehavior::isOwnedByUser()
If I change the method call to isOwnedBy($TestModel, 'user', 1, new User(), 1); this works, so it looks like for some reason the mapped methods aren't working during the unit test. I have tested the mapped methods in a controller and I get no errors.
I wondered if it was down to how I was loading the behaviour into the model. I couldn't find any documentation in the cookbook on how to properly test Behaviours like there is with Components, Helpers, etc... So I just used the same techniques that the Core Behaviour tests use (Found in Cake/Test/Case/Model/Behavior/).
I did think maybe it could have been down to the fact that I am overwriting the ModelBehavior::setup() method, but I tried adding parent::setup($model, $settings) at the start of the setup method and I still get the same error. I am not overwriting any of the other ModelBehavior methods.
I guess I could just use the OwnableBehavior::isOwnedBy() method, but I'd quite like to know if I could get the mapped methods to work during a unit test.
The solution I have found is replacing this line:
$result = $TestModel->Behaviors->Ownable->isOwnedByUser(...);
with:
$result = $TestModel->isOwnedByUser(...);
So it's just a case of using it more like you would in the application, calling the behaviour method directly from the model. I don't know if this ruins the idea of a unit test and makes it more into integration testing though.

Making Symfony2 unit tests more DRY by extending WebTestCase

A lot of my tests have a lot of the same setUp()/tearDown() stuff going on. It seems dumb to copy and paste the same code into every single one of my unit tests. I think I want to create a new test class that extends WebTestCase that my other tests can extend.
My problem is that I don't really know how. First of all, where's the most appropriate place to put this new class? I tried making one just inside my Tests folder, but then none of my tests could actually find the class. Maybe I just don't understand namespaces.
Has anyone extended WebTestCase before in the way I'm talking about? If so, how did you do it?
I haven't done this, but I'd probably just do it like so
src/Your/Bundle/Test/WebTestCase.php
<?php
namespace Your\Bundle\Test
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as WTC;
class WebTestCase extends WTC
{
// Your implementation of WebTestCase
}
In my tests I usually extend the WebTestCase the way Peter proposed it. Additionally I use require_once to make the AppKernel available in my WebTestCase:
<?php
namespace My\Bundle\Tests;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase as BaseWebTestCase;
require_once(__DIR__ . "/../../../../app/AppKernel.php");
class WebTestCase extends BaseWebTestCase
{
protected $_application;
protected $_container;
public function setUp()
{
$kernel = new \AppKernel("test", true);
$kernel->boot();
$this->_application = new \Symfony\Bundle\FrameworkBundle\Console\Application($kernel);
$this->_application->setAutoExit(false);
...
My tests then look like this:
<?php
namespace My\Bundle\Tests\Controller;
use My\Bundle\Tests\WebTestCase;
class DefaultControllerTest extends WebTestCase
{
public function testIndex()
{
...
You don't need to extend WebTestCase to include AppKernel. You can use the following approach
$client = static::createClient();
self::$application = new Application($client->getKernel());
This question is really old but it ranks quite highly on Google, so I thought I'd add my solution.
I extended WebTestCase with a default setUp method and a logIn method so I could more easily run authenticated tests.
It seems you can't add standard classes to the tests directory because the unit tests won't find them. I'm not sure why. My solution was to add a directory src/_TestHelpers and put my helper classes in there.
So I have:
# src/_TestHelpers/ExtendedWTC.php
namespace _TestHelpers;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ExtendedWTC extends WebTestCase
{
# Do your cool extending here
}
and
# tests/AppBundle/Controller/DefaultControllerTest.php
namespace Tests\AppBundle;
use _TestHelpers\ExtendedWTC
class DefaultControllerTest extends ExtendedWTC
{
# Your tests here, using your cool extensions.
}
Note: I'm using the Symfony 3 directory structure, hence why my tests are in tests/ and not src/AppBundle/Tests/.
I hope this helps someone...