Welcome Guest, Not a member yet? Register   Sign In
getting uri_string() to work with Controller tests (phpunit)
#1

I cannot make uri_string() and site_url() functions work within controllers when run through phpunit.

For example, in a freshly installed composer project I add this route (in app/Config/Routes.php):

PHP Code:
$routes->get('checkup/first/(:segment)''Checkup::first/$1'); 

This controller (app/Controllers/Checkup.php):

PHP Code:
<?php

namespace App\Controllers;

class 
Checkup extends BaseController
{
    public function first($second '')
    {
        return 'uri_string() returns: ' 
        uri_string() 
        '; Segment after first: ' $second
        
'; current_url() returns: ' current_url();
    }


And this test (tests/app/Controllers/CheckupTest.php)

PHP Code:
<?php

namespace CodeIgniter;

use 
CodeIgniter\Test\CIUnitTestCase;
use 
CodeIgniter\Test\ControllerTestTrait;

final class 
CheckupTest extends CIUnitTestCase
{
    use ControllerTestTrait;

    public function testFirst()
    {
        // $request and $response were added while tinkering, the test produces the same results without them
        $request = new \CodeIgniter\HTTP\IncomingRequest(
            new \Config\App(),
            new \CodeIgniter\HTTP\URI('http://localhost:8080/checkup/first/second'),
            null,
            new \CodeIgniter\HTTP\UserAgent()
        );
        $response = new \CodeIgniter\HTTP\Response(
            new \Config\App(),
            new \CodeIgniter\HTTP\URI('http://localhost:8080/checkup/first/second'),
        );
        $result $this->withURI('http://localhost:8080/checkup/first/second')
            ->withRequest($request)
            ->withResponse($response)
            ->controller(\App\Controllers\Checkup::class)
            ->execute('first''second');

        // check the response is ok
        $this->assertTrue($result->isOK());
        
        
// this should fail (as this string IS what we see in browser)
        $this->assertTrue($result->DontSee('uri_string() returns: checkup/first/second; Segment after first: second;'));
        
        
// this should fail, but it does not, as uri_string() does not work:
        $this->assertTrue($result->see('uri_string() returns: ; Segment after first: second;'));
        
        
// this should fail (as this string IS what we see in browser)
        $this->assertTrue($result->DontSee('current_url() returns: http://localhost:8080/index.php/checkup/first/second'));
        
        
//echo $result->getBody(); // uncomment to see what is actually returned in the cli
    }


then I run
PHP Code:
vendor/bin/phpunit 

I wrote in comments where the functions go wrong in the test (the test should fail, but it succeeds).

Am I missing something, or is this a bug?
==

Donatas G.
Reply
#2

The following test passes.

PHP Code:
    public function testFirst()
    {
        $result $this->withURI('http://example.com/checkup/first/second')
            ->controller(\App\Controllers\Checkup::class)
            ->execute('first''second');

        // check the response is ok
        $this->assertTrue($result->isOK());

        $result->see('uri_string() returns: checkup/first/second; Segment after first: second;');
        $result->dontSee('uri_string() returns: ; Segment after first: second;');
        $result->see('current_url() returns: http://example.com/index.php/checkup/first/second');

        // echo $result->getBody(); // uncomment to see what is actually returned in the cli
    
Reply
#3

(08-08-2023, 11:03 PM)kenjis Wrote: The following test passes.

PHP Code:
    public function testFirst()
    {
        $result $this->withURI('http://example.com/checkup/first/second')
            ->controller(\App\Controllers\Checkup::class)
            ->execute('first''second');

        // check the response is ok
        $this->assertTrue($result->isOK());

        $result->see('uri_string() returns: checkup/first/second; Segment after first: second;');
        $result->dontSee('uri_string() returns: ; Segment after first: second;');
        $result->see('current_url() returns: http://example.com/index.php/checkup/first/second');

        // echo $result->getBody(); // uncomment to see what is actually returned in the cli
    

mhm, not really. Actually phpunit does not count $result->see() as assertions, so when I run

vendor/bin/phpunit --filter CheckupTest

the test does pass, but reports only one assertion.  And whatever I write in the $result->see('') argument, nothing changes, the tests pass.

And once I enclose the $result->see() within $this->assertTrue(), the tests fail (but report correct number of assertions).
==

Donatas G.
Reply
#4

Oh, I thought see() was an assertion method.
https://codeigniter4.github.io/CodeIgnit...om-helpers
But it just returns bool. The documentation is comfusing.

You are correct. The output is:
Code:
uri_string() returns: ; Segment after first: second; current_url() returns: http://example.com/index.php
Reply
#5

(08-09-2023, 01:12 PM)kenjis Wrote: Oh, I thought see() was an assertion method.
https://codeigniter4.github.io/CodeIgnit...om-helpers
But it just returns bool. The documentation is comfusing.

Yep, that is what I thought as well. A unit testing tutorial, like there is with forms or validation, would be really great to have.

However, when I started implementing what I was reading, I did make progress through trial and error and a lot of additional reading.

Anyway, any ideas why uri_string would not work here, with controller tests?

It does seem to work in integration tests (in a self-contained example), although I do seem to be loosing the last fragment when doing integration tests in my app. Need to investigate that as well...
==

Donatas G.
Reply
#6

(This post was last modified: 08-09-2023, 05:14 PM by kenjis.)

I sent a PR to improve the docs: https://github.com/codeigniter4/CodeIgniter4/pull/7804

uri_string() has hidden dependencies for getting the current URI.
But Controller tests do not setup the dependencies correctly.
That's why uri_string() does not work in testing.

The current URI handling in the framework is very complex. It depends a lot of things.
So probably to fix it is not easy.

I'm trying to clean up the process in 4.4 branch:
https://github.com/codeigniter4/CodeIgniter4/pull/7282
See the tests would pass: https://github.com/codeigniter4/CodeIgni...112ea2c025
Reply
#7

Try this:
PHP Code:
    public function testFirst()
    {
        $request = new \CodeIgniter\HTTP\IncomingRequest(
            new \Config\App(),
            new \CodeIgniter\HTTP\URI('http://example.com/checkup/first/second'),
            null,
            new \CodeIgniter\HTTP\UserAgent()
        );
        // Force to fix the URI path
        $request->setPath('checkup/first/second');

        $result $this->withURI('http://example.com/checkup/first/second')
            ->withRequest($request)
            ->controller(\App\Controllers\Checkup::class)
            ->execute('first''second');

        // check the response is ok
        $this->assertTrue($result->isOK());

        $result->assertSee('uri_string() returns: checkup/first/second; Segment after first: second;');
        $result->assertDontSee('uri_string() returns: ; Segment after first: second;');
        $result->assertSee('current_url() returns: http://example.com/index.php/checkup/first/second');

        // echo $result->getBody(); // uncomment to see what is actually returned in the cli
    
Reply
#8

(08-09-2023, 05:22 PM)kenjis Wrote: Try this:
PHP Code:
    public function testFirst()
    {
        /* */
    

This does work, thanks!
==

Donatas G.
Reply




Theme © iAndrew 2016 - Forum software by © MyBB