Janvi
Janvi

Reputation: 125

How to use server variables in PHPUnit Test cases?

I am testing modules using PHPUnit Test cases. All the things working fine but when i use $_SERVER['REMOTE_ADDR'] it gives fatal error and stops execution.

CategoryControllerTest.php

<?php
namespace ProductBundle\Controller\Tests\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class CategoryControllerTest extends WebTestCase {

     protected function setUp() {
        static::$kernel = static::createKernel();
        static::$kernel->boot();
        $this->container = static::$kernel->getContainer();
        $this->em = static::$kernel->getContainer()->get('doctrine')->getManager();
    }

    public function testCategory() {
        $ip_address = $_SERVER['REMOTE_ADDR'];
        $client = static::createClient(
          array(), array('HTTP_HOST' => static::$kernel->getContainer()->getParameter('test_http_host')
        ));

        $crawler = $client->request('POST', '/category/new');
        $client->enableProfiler();

        $this->assertEquals('ProductBundle\Controller\CategoryController::addAction', $client->getRequest()->attributes->get('_controller'));
        $form = $crawler->selectButton('new_category')->form();
        $form['category[name]'] = "Electronics";
        $form['category[id]']   = "For US";
        $form['category[ip]']   = $ip_address;
        $client->submit($form);

        $this->assertTrue($client->getResponse()->isRedirect('/category/new')); // check if redirecting properly
        $client->followRedirect();
        $this->assertEquals(1, $crawler->filter('html:contains("Category Created Successfully.")')->count());
    }
}

Error

There was 1 error:

1) ProductBundle\Tests\Controller\CategoryControllerTest::testCategory Undefined index: REMOTE_ADDR

I have tried to add it in setUp() function but it's not working as well.

Upvotes: 6

Views: 8659

Answers (3)

HAL McZus
HAL McZus

Reputation: 11

You can either create another class that will return the server var then mock it.

Or you can set/unset the server var directly into your test case. Did it with PHPUnit 6.2.2 :

 /**
 * Return true if the user agent matches a robot agent
 */
public function testShouldReturnTrueIfRobot()
{
    $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)';

    $this->configMock->method('getRobotUserAgents')
        ->willReturn('bot|crawl|slurp|spider|mediapartner');

    $test = $this->robotTest->isBot();

    static::assertTrue($test);
}

/**
 * Test return false if no user agent
 */
public function testShouldReturnFalseIfNoAgentUser()
{
    unset($_SERVER['HTTP_USER_AGENT']);

    $test = $this->robotTest->isBot();

    static::assertFalse($test);
}

Where tested method is :

 /**
 * Detect if current user agent matches a robot user agent
 *
 * @return bool
 */
public function isBot(): bool
{
    if (empty($_SERVER['HTTP_USER_AGENT'])) {
        return false;
    }

    $userAgents = $this->config->getRobotUserAgents();
    $pattern = '/' . $userAgents . '/i';

    return \preg_match($pattern, $_SERVER['HTTP_USER_AGENT']);
}

Upvotes: 1

Gopal Joshi
Gopal Joshi

Reputation: 2358

Create service which returns ip address and mock the service in test case.

Here, create controller and service as UserIpAddress. get() will return ip address of user.

service.yml

UserIpAddress:
    class: AppBundle\Controller\UserIpAddressController
    arguments: 
    container: "@service_container"  

UserIpAddressController.php

class UserIpAddressController
{
  public function get()
  {
    return $_SERVER['REMOTE_ADDR'];
  }
}

Create mock of "UserIpAddress" service. It will override existing service. Use 'UserIpAddress' service to get ip address in your project.

CategoryControllerTest.php

$UserIpAddress = $this->getMockBuilder('UserIpAddress')
    ->disableOriginalConstructor()
    ->getMock();

$UserIpAddress->expects($this->once())
  ->method('get')
  ->willReturn('192.161.1.1'); // Set ip address whatever you want to use

Now, get ip address using $UserIpAddress->get();

Upvotes: 0

Loek
Loek

Reputation: 4135

Technically, you haven't sent a request to your application yet, so there is no remote address to refer to. That in fact is what your error is telling us too.

To work around this:

  1. move the line to be below:

    // Won't work, see comment below    
    $crawler = $client->request('POST', '/category/new');
    
  2. Or you could make up an IP address and test with that. Since you're only using the IP to save a model, that will work just as well.

Like @apokryfos mentioned in the comments, it's considered bad practice to access superglobals in test cases. So option 2 is probably your best choice here.

Upvotes: 1

Related Questions