Zend_Test_PHPUnit_ControllerTestCase: Test view parameters and not rendered output - php

I'm using Zend_Test_PHPUnit_ControllerTestCase to test my controllers. This class provides various ways to test the rendered output, but I don't want to get my view scripts involved. I'd like to test my view's vars. Is there a way to access to the controllers view object?
Here is an example, what I'm trying to do:
<?php
class Controller extends Zend_Controller_Action
{
public function indexAction()
{
$this-view->foo = 'bar';
}
}
class ControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
public function testShowCallsServiceFind()
{
$this->dispatch('/controller');
//doesn't work, there is no such method:
$this->assertViewVar('foo', 'bar');
//doesn't work, end_Test_PHPUnit_ControllerTestCase has no getView method:
$this->assertEquals(
'bar',
$this->getView()->foo
);
}
}

If you really must assert against the view, get it with Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer')->view and assert against it.
The intention of Zend_Test however is that you would assert against the actual response, using an xpath query or something similar. this will allow you to fully test your application, instead of just a part of it.
if you simply assert that the view contains a var and that it is equal to a given thing, you are not really testing that it has been used in the right way.

1) Zend_Test_PHPUnit_ControllerTestCase::_resetPlaceholders() uses the singelton obtained in Zend_Registry::getInstance() and searches it for placeholders. Maybe you could mimic that behaviour.
2) Did you try $view = Zend_Layout::getMvcInstance()->getView() already? I haven't tested controllers yet but since the test cases includes singeltons, perhaps that wouldn't be such a far out guess.

Related

How to test Laravel 5 controllers methods

We have Laravel 5 controllers method:
public function getInput()
{
$input = \Request::all();
$links = $input['links'];
$this->startLinks = explode("\n", $links);
return $this;
}
How can we test this single method? How to pass POST request with data to this method? And how to create instance of this controller class in my test method?
This looks like a method which probably shouldn't belong in a controller. If you are serious about testing, I'd highly recommend reading up on the repository pattern. When testing, it will make your life a lot easier to have everything abstracted out of the controllers.=
With that said though, this is still very testable. The main idea is to figure out what needs to be tested and ONLY test that. This means we don't care what the dependencies are doing, only that they are doing and returning something which the rest of the method will need. In this case, it's the Request facade.
Then you want to make sure the variables are set appropriately and that the method returned an instance of that class. It actually ends up being pretty straight forward.
Should look something like this...
public function testGetInput()
{
$requestParams = [
'links' => "somelink.com\nsomeotherlink.com\nandanotherlink.com\ndoesntmatter.com"
];
// Here we are saying the \Request facade should expect the all method to be called and that all method should
// return some pre-defined things which we will use in our asserts.
\Request::shouldReceive('all')->once()->andReturn($requestParams);
// Here we are just using Laravel's IoC container to instantiate your controller. Change YourController to whatever
// your controller is named
$class = App::make('YourController');
// Getting results of function so we can test that it has some properties which were supposed to have been set.
$return = $class->getInput();
// Again change this to the actual name of your controller.
$this->assertInstanceOf('YourController', $return);
// Now test all the things.
$this->assertTrue(isset($return->startLinks));
$this->assertTrue(is_array($return->startLinks));
$this->assertTrue(in_array('somelink.com', $return->startLInks));
$this->assertTrue(in_array('nsomeotherlink.com', $return->startLInks));
$this->assertTrue(in_array('nandanotherlink.com', $return->startLInks));
$this->assertTrue(in_array('ndoesntmatter.com', $return->startLInks));
}
I think you are looking for this.
If your test class extends TestCase you will get a lot of helper methods which will do heavy lifting for you.
function testSomething() {
// POST request to your controller#action
$response = $this->action('POST', 'YourController#yourAction', ['links' => 'link1 \n link2']);
// you can check if response was ok
$this->assertTrue($response->isOk(), "Custom message if something went wrong");
// or if view received variable
$this->assertViewHas('links', ['link1', 'link2']);
}
Codeception extends this functionality even further.

PHP: How to render the view at the end?

I'm trying to create my own little PHP-Framework just for fun and to learn.
But now I stuck with the View.
class Index extends Controller {
function __construct() {
parent::__construct();
$this->view->msg = 'This message is sended over the view.';
$this->view->content = 'This is the INDEX-Content.';
$this->view->render('index/index');
}
public function something() {
// do something
// and render it
$this->view->content = 'This is the content from something.'
}
So what I can do is to misuse the __destruct and render here my output. But I guess that is against the purpose of this method.
When I compare my intention with e.g. Zend Framework or Laravel they use e.g. an after() method to render a view.
But I do not understand which method can do this. The constructor is the first, the destructor the last and everything between it has to be called to work.
Are there any "magic" methods for this?
You should handle your HTTP I/O
This is how you can output
This is how a request is executed
This is how the action is triggerd
Sniff through the repo as much as you can, Kohana is a simple yet powerfull framework. (you can learn a thing or two)
You can do something like this in your main Controller class :
public function __call($method,$arguments) {
if(method_exists($this, $method)) {
call_user_func_array(array($this,$method),$arguments); //this is where the function is called
$this->render();
}
}
You can eliminate in hear constructors, destruct and other functions that you do not want to automatically render.
You can also have a variable in your main Controller class, autoRender set default to false and just set it to true when you want to produce a predefined output.
Also in the _call function, you can use the $method variable to have a predefined name for your view. Like for example lets say you would have a folder in your framework called Views and in there you would have a file called something.view_extension.
You can send to render like this : $this->render($method.'.view_extension');
Just a bulk idea you can work around. :)

PHP: Overwriting of static methods does not work as expected

I have two php classes: TestUK and TestFR, which extends TestUK.
Both classes are used to generate requests to two different domains. But something is going wrong with the inheritence, and I fail to understand why.
I have one method named "get_domain", which is overwritten to get the domain that should actually be used. If I call it directly via TestFR::get_domain(), i receive the expected result. But if I call a method that is not overwritten by TestFR, but which uses self::get_domain(), I receive the wrong domain.
If I simply copy-and-paste the method do_stuff from TestUK to TestFR, then I get the expected result. But copy-pasting identical (!) code is just what I was trying to avoid.
What is the reason for this? I do not have that much experience with class inheritence in PHP, but I would have expected this to work without problems. Or is my approch completely flawed?
<?php
class TestUK {
const DOMAIN_UK = 'http://www.domain.co.uk';
const DOMAIN_FR = 'http://www.domain.fr';
static function get_domain(){
return self::DOMAIN_UK;
}
static function do_stuff(){
echo self::get_domain();
}
}
class TestFR extends TestUK {
static function get_domain(){
return self::DOMAIN_FR;
}
}
// Works as intended:
// Expected and actual output: http://www.domain.fr
echo TestFR::get_domain();
// Does NOT work as intendes:
// Expected Output: http://www.domain.fr
// Actual Output: http://www.domain.co.uk
TestFR::do_stuff();
?>
This is because the keyword self refers to the class where it appears in, not to the class on which the method was called. For the latter functionality you will have to use late static binding with the static keyword:
static function do_stuff(){
echo static::get_domain();
}
That said, this code smells really bad. Why is everything static and not simply an instance method? Why is TestFR extending TestUK instead of both extending an abstract base class Test?
It would be much better to convert everything to non-static methods, and as a bonus your problem would immediately disappear.
call it like (if you are using php >= 5.3
static::get_domain();

Using PHPUnit to test helper functions

Let's say I want to test a simple helper that takes a class name as an argument and makes a redirection.
How am I supposed to test this if the function is called in many places from inside a couple of controllers? Should I test every class name that was passed as a parameter in the whole code (write them in the provider function myself)? Or is there a magical function which does that for me?
Your question is the exact reason why dependency injection -- when done correctly (not how most popular frameworks "implement" it) -- is touted as the ultimate in code testability.
To understand why, lets look at how "helper functions" and class-oriented programming make your controllers difficult to test.
class Helpers {
public static function myHelper() {
return 42;
}
}
class MyController {
public function doSomething() {
return Helpers::myHelper() + 100;
}
}
The entire point of unit testing is to verify that "units" of code work in isolation. If you can't isolate functionality, your tests are meaningless because their results could be tainted by the behavior of the other code involved. This can result in what statisticians call Type I and Type II errors: basically, this means you can get test results that might be lying to you.
In the code above, the helper cannot be easily mocked to determine that MyController::doSomething works in complete isolation from outside influences. Why not? Because we can't "mock" the behavior of the helper method to guarantee our doSomething method actually adds 100 to the helper result. We're stuck with the helper's exact behavior (returning 42). This is a problem that correct object-orientation and inversion of control eliminate entirely. Let's consider an example of how:
If MyController asks for it's dependencies instead of using the static helper function , it becomes trivial to mock the outside influences. Consider:
interface AnswerMachine {
public function getAnswer();
}
class UltimateAnswerer implements AnswerMachine {
public function getAnswer() {
return 42;
}
}
class MyController {
private $answerer;
public function __construct(AnswerMachine $answerer) {
$this->answerer = $answerer;
}
public function doSomething() {
return $this->answerer->getAnswer() + 100;
}
}
Now, it's trivially simple to test that MyController::doSomething does in fact add 100 to whatever it gets back from the answer machine:
// test file
class StubAnswerer implements AnswerMachine {
public function getAnswer() {
return 50;
}
}
$stubAnswer = new StubAnswerer();
$testController = new MyController($stubAnswerer);
assert($testController->doSomething() === 150);
This example also demonstrates how the correct use of interfaces in your code can greatly simplify the testing process. Test frameworks like PHPUnit make it very easy to mock interface definitions to perform exactly what you want them to in order to test the isolated functionality of code units.
So I hope these very simple examples demonstrate how powerful dependency injection is when it comes to testing your code. But more importantly, I hope they demonstrate why you should be wary if your framework of choice is using static (just another name for global), singletons, and helper functions.
You cannot test each possible combination of parameters to all the functions you need to test; it will take you longer than the life of the universe. So you use Human Intelligence (some might call it cheating ;-). Test it just once, in this case with a mock controller as the parameter.
Then look at your code and ask yourself if any other object passed in is really going to have it behave differently. For something you describe as a "simple helper" maybe the answer is no. But, if yes, how? Create another mock controller class that simulates that different behaviour. E.g. this second controller might not have the function your helper class expects to call. You expect an exception to be thrown. Create the unit test for that.
Repeat until satisfied.

Zend Framework: Pass by reference to view helper not working

Here is a simple view helper (notice the pass-by-reference argument):
class Zend_View_Helper_MyViewHelper extends Zend_View_Helper_Abstract
{
public function MyViewHelper(&$array)
{
unset($array['someExistingKey']);
}
}
This does not work in the view. $array['someExistingKey'] is still set (except within the immediate context of the method). Zend must be doing something to prevent the array from being passed in by reference. Any ideas on a solution?
When you call $this->MyViewHelper($array) from your templates you are not actually calling the helper class directly, Zend_View is instantiating the class and calling it for you. So I think you might have trouble getting this working. Your best bet is probably to use Zend_Registry, or refactor to take a different approach not requiring a global.
I just thought of a workaround. You just have to call the helper manually, instead of letting ZF call it through call_user_func_array.
Ref.php
class Zend_View_Helper_Ref extends Zend_View_Helper_Abstract
{
public function removeFromRef(&$ref)
{
// change your var value here
unset($ref['key']);
}
/**
* ZF calls this for us, but we'll call what we want, so you can skip this.
*/
// public function ref()
// {}
}
As you can see, you can skip the convention of having to name your main method as the filename, but I still recommend it.
Now, you can pass references in views/controllers:
// in view:
$this->getHelper('Ref')->removeFromRef($someVar2Change);
// in controller
$this->view->getHelper('Ref')->removeFromRef($someVar2Change);
Basically, this is what $this->ref() does: gets the helper, then calls call_user_func_array.
Some people may have problems using $this->getHelper('Ref')->ref() instead of $this->ref() though, but it works.

Categories