Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trouble getting a simple check to work #47

Closed
bfintal opened this issue Sep 9, 2015 · 17 comments
Closed

Trouble getting a simple check to work #47

bfintal opened this issue Sep 9, 2015 · 17 comments
Labels
Needs Reporter Feedback Issue has open questions pending original reporter feedback

Comments

@bfintal
Copy link

bfintal commented Sep 9, 2015

Okay so I dunno if I'm just missing something here. I've trimmed everything down to the very very basics. I have WP_Mock setup, and I have a few working unit tests already. I wanted to check if an action was being done do_action in a function although with anything I do, I get this error after the test:

Mockery\Exception\InvalidCountException: Method intercepted() from Mockery_0__intercept should be called
 at least 1 times but called 0 times.
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/vendor/mockery/mockery/library/Mockery/CountValidator/AtLeast.php:48
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/vendor/mockery/mockery/library/Mockery/Expectation.php:271
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/vendor/mockery/mockery/library/Mockery/ExpectationDirector.php:120
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/vendor/mockery/mockery/library/Mockery/Container.php:297
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/vendor/mockery/mockery/library/Mockery/Container.php:282
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/vendor/mockery/mockery/library/Mockery.php:142
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/vendor/10up/wp_mock/WP_Mock.php:112
/vagrant/www/wordpress-default/wp-content/plugins/sumo-search/tests/test-titan-framework-checker.php:12

This is my back to basics test file:

<?php

class TitanFrameworkCheckerTest extends WP_UnitTestCase {

    public function setUp() {
        parent::setUp();
        \WP_Mock::setUp();
    }

    public function tearDown() {
        parent::tearDown();
        \WP_Mock::tearDown();
    }

    function test_perform_check() {
        $o = new TitanFrameworkChecker();

        \WP_Mock::expectAction( 'my_action' );

        $result = $o->perform_check();

    }

}

Now this is the code being checked:

class TitanFrameworkChecker {

    public function perform_check() {
        do_action( 'my_action' );
    }

}

That test code above gives out the same error for me. I can't get this simple one to work. I've also tried with other functions like expectFilterAdded.

I would appreciate any help on this.

@bfintal
Copy link
Author

bfintal commented Sep 9, 2015

Or this one also:

Test:

function test_perform_check() {
    \WP_Mock::onFilter( 'special_filter' )
        ->with( 'something' )
        ->reply( 'altered' );

    $response = test_function();

    $this->assertEquals( 'altered', $response );

}

Code:

function test_function() {
    return apply_filters( 'special_filter', 'something' );
}

It feels like WP_Mock is there but isn't running or something. Although the setUp function is running.

@johnpbloch
Copy link
Contributor

Hey @bfintal thanks for filing the issue. This certainly seems serious. Could you please provide the version of WP Mock you're using? To get that, you can run composer info -i and copy over the whole line with WP Mock in it.

Also, could you give us a little more information your setup? Judging by your use of WP_UnitTestCase it would appear you're using the WordPress core test framework together with WP_Mock. Is that the case?

@bfintal
Copy link
Author

bfintal commented Sep 10, 2015

I'm using 1.0.x-dev (also tried dev-master before)

10up/wp_mock 1.0.x-dev f58b1a7

My setup is:

  • VVV
  • PHP_CodeCoverage 2.2.2
  • PHP 5.5.9-1ubuntu4.11
  • PHPUnit 4.3.5

Yup that's what I'm trying to do. Although I have also tried just extending PHPUnit_Framework_TestCase as per the readme.md while using the same setup, I'm a bit new to unit testing so I don't know if that is causing any problems. I can perform normal tests fine though.

The project I'm trying to build unit tests on is Titan Framework, it's grown quite a bit so it definitely needs unit testing. The whole setup with the bootstrap and install scripts are in the repo under the bin & tests directories.

@goodpic
Copy link

goodpic commented Sep 10, 2015

Hello, I have exactly the same error with the similar simple test case. I am using vccw on Mac. I googled the error but could not figure out the cause of this error. I am new to WP_Mock so I might be missing something though... Thanks for your help!

$ composer info -i
10up/wp_mock          dev-master 3e032aa A mocking library to take the pain...
antecedent/patchwork  1.3.4              A pure PHP library that lets you r...
hamcrest/hamcrest-php v1.2.2             This is the PHP port of Hamcrest M...
mockery/mockery       0.9.4              Mockery is a simple yet flexible P...
1) WashokuAdminTest::test_init
Mockery\Exception\InvalidCountException: Method intercepted() from Mockery_0__intercept should be called
 at least 1 times but called 0 times.

/var/www/wordpress/wp-content/plugins/washoku-admin/vendor/mockery/mockery/library/Mockery/CountValidator/AtLeast.php:48
/var/www/wordpress/wp-content/plugins/washoku-admin/vendor/mockery/mockery/library/Mockery/Expectation.php:271
/var/www/wordpress/wp-content/plugins/washoku-admin/vendor/mockery/mockery/library/Mockery/ExpectationDirector.php:120
/var/www/wordpress/wp-content/plugins/washoku-admin/vendor/mockery/mockery/library/Mockery/Container.php:297
/var/www/wordpress/wp-content/plugins/washoku-admin/vendor/mockery/mockery/library/Mockery/Container.php:282
/var/www/wordpress/wp-content/plugins/washoku-admin/vendor/mockery/mockery/library/Mockery.php:142
/var/www/wordpress/wp-content/plugins/washoku-admin/vendor/10up/wp_mock/WP_Mock.php:112
/var/www/wordpress/wp-content/plugins/washoku-admin/tests/test-sample.php:11

My test is

class WashokuAdminTest extends PHPUnit_Framework_TestCase {

    public function setUp() {
        \WP_Mock::setUp();
    }

    public function tearDown() {
        \WP_Mock::tearDown();
    }

    public function test_init() {

        $this->wadmin = new WashokuAdmin;
        \WP_Mock::expectActionAdded( 'admin_menu', array ($this->wadmin, 'remove_sidemenu' ) );
        $this->wadmin->init();
  }
}

The plugin function is:

class WashokuAdmin {

  function init() {
        add_action( 'admin_menu', array( $this, 'remove_sidemenu' ) );
        add_action( 'do_meta_boxes', array( $this, 'remove_plugin_metaboxes' ) );
        register_activation_hook( __FILE__, array( $this, 'permit_upload_to_contributor' ) );
        add_filter( 'get_user_metadata', array( $this, 'disable_tgmpa_notice'), 10, 4);
  }
}

@bfintal
Copy link
Author

bfintal commented Sep 10, 2015

@goodpic Glad to know I'm not alone in this one :)

I think you should do this though to catch the action:

\WP_Mock::expectActionAdded( 'admin_menu', array( $this->wadmin, 'remove_sidemenu' ) );

@goodpic
Copy link

goodpic commented Sep 10, 2015

@bfintal Oh! thank you! I fixed the line (and updated the comment), but still see the same error.

@bfintal
Copy link
Author

bfintal commented Sep 18, 2015

@johnpbloch Any clues on this?

@johnpbloch
Copy link
Contributor

At this time, use of WP Mock in conjunction with the WordPress core testing framework is not supported. WP Mock was created to remove WordPress core and all of its state from the unit testing equation, so it doesn't really work well together with the code it was meant to replace.

@johnpbloch
Copy link
Contributor

I haven't closed this yet because I'm open to suggestions for use-cases that would make this pairing worth supporting. I can certainly see the value of using both separately, one for unit tests and one for integration tests, I'm just having trouble imagining a scenario where using both together at the same time in the same context is a value-add.

But like I said, I'm happy to hear ideas. :D

@johnpbloch johnpbloch added the Needs Reporter Feedback Issue has open questions pending original reporter feedback label Sep 18, 2015
@bfintal
Copy link
Author

bfintal commented Sep 19, 2015

Sorry, I'm really new to PHP Unit and unit testing in general so I don't quite understand what you mean by not supporting the core testing framework. Does extending WP_UnitTestCase trigger this? If that's the case, switching to PHPUnit_Framework_TestCase still shows the same error.

How would you use WP_Mock without the core testing framework? Is there something in the bootstrap file or the unit test installer that needs to be removed?

@johnpbloch
Copy link
Contributor

Does extending WP_UnitTestCase trigger this?

The core test framework itself triggers this. The reason being it loads WordPress itself. WP Mock works by expecting WordPress not to be present and then defining any WordPress functions or classes as needed.

How would you use WP_Mock without the core testing framework?

To see how you can use WP Mock, check out WP Async Task.

Is there something in the bootstrap file or the unit test installer that needs to be removed?

All of it. The bootstrap from the core framework is what loads WordPress. So the whole thing needs to go. Again, WP Async Task has a good example of what a WP Mock bootstrap file ought to look like. And to be perfectly honest, you don't even need that. You could just use vendor/autoload.php as your bootstrap file. As more complex needs arise, you can add to your bootstrap (such as ensuring certain constants are always defined, etc.).

@bfintal
Copy link
Author

bfintal commented Sep 21, 2015

I see, so this means that the main problem within my setup is that I ran: wp scaffold on the project as my starting point. That generated the bootstrap file I'm currently using now which is loading the core WP tests. Just including require_once 'vendor/autoload.php'; with the current bootstrap won't work.

Okay new problem. I tried removing the existing bootstrap and just used the one in vendor/autoload.php. When I run phpunit, it doesn't start up. It just exits abruptly and shows the prompt without any error messages. I tried making it show the errors & startup errors but nothing's showing up. I'm running the phpunit that came with VVV. Using composer to get phpunit and running it also shows nothing.

@johnpbloch
Copy link
Contributor

Are your tests still extending WP_UnitTestCase? If so, they should be extending \WP_Mock\Tools\TestCase.

@arippberger
Copy link

Hmmm - I too am having some issues getting a simple example to work.

I've attached an image of my plugins directory structure:
screen shot 2015-10-05 at 4 09 05 pm

I'm using the simple bootstrap file

<?php
require_once __DIR__ . '/vendor/autoload.php';

I'm using examples from the documentation in my test-restaurant-connect.php file (although I extended from TestCase instead)

<?php

/**
 * Class MyTestClass
 * @test
 */
class MyTestClass extends \WP_Mock\Tools\TestCase {
    public function setUp() {
        \WP_Mock::setUp();
    }

    public function tearDown() {
        \WP_Mock::tearDown();
    }

    /**
     * Assume that my_permalink_function() is meant to do all of the following:
     * - Run the given post ID through absint()
     * - Call get_permalink() on the $post_id
     * - Pass the permalink through the 'special_filter' filter
     * - Trigger the 'special_action' WordPress action
     */
    public function test_my_permalink_function() {
        \WP_Mock::wpFunction( 'get_permalink', array(
            'args' => 42,
            'times' => 1,
            'return' => 'http://example.com/foo'
        ) );

        \WP_Mock::wpPassthruFunction( 'absint', array( 'times' => 1 ) );

        \WP_Mock::onFilter( 'special_filter' )
                ->with( 'http://example.com/foo' )
                ->reply( 'https://example.com/bar' );

        \WP_Mock::expectAction( 'special_action', 'https://example.com/bar' );

        $result = my_permalink_function( 42 );

        $this->assertEquals( 'https://example.com/bar', $result, 'Result was ' . $result );
    }

    public function test_uses_get_post() {
        global $post;

        $post = new \stdClass;
        $post->ID = 42;
        $post->special_meta = '<p>I am on the end</p>';

        \WP_Mock::wpFunction( 'get_post', array(
            'times' => 1,
            'args' => array( $post->ID ),
            'return' => $post,
        ) );

        /*
         * Let's say our function gets the post and appends a value stored in
         * 'special_meta' to the content.
         */
        $results = special_the_content( '<p>Some content</p>' );

        /*
         * In addition to failing if this assertion is false, the test will fail
         * if get_post is not called with the arguments above.
         */
        $this->assertEquals( '<p>Some content</p><p>I am on the end</p>', $results );
    }
}

In my main plugin file I define the following functions:

function my_permalink_function( $post_id ) {
    $permalink = get_permalink( absint( $post_id ) );
    $permalink = apply_filters( 'special_filter', $permalink );

    do_action( 'special_action', $permalink );

    return $permalink;
}

function special_the_content( $content ) {
    return $content . '<p>I am on the end</p>';
}

When I run phpunit from under the plugin directory I receive the following error

PHP Fatal error:  Call to undefined function my_permalink_function() in Unknown on line 0
PHP Stack trace:
PHP   1. {main}() /usr/local/src/composer/vendor/phpunit/phpunit/phpunit:0
PHP   2. PHPUnit_TextUI_Command::main($exit = *uninitialized*) /usr/local/src/composer/vendor/phpunit/phpunit/phpunit:56
PHP   3. PHPUnit_TextUI_Command->run($argv = array (0 => '/usr/local/bin/phpunit'), $exit = TRUE) /usr/local/src/composer/vendor/phpunit/phpunit/src/TextUI/Command.php:138
PHP   4. PHPUnit_TextUI_TestRunner->doRun(...
...
...
...
PHP  12. MyTestClass->test_my_permalink_function()

So this looks like my main plugin file isn't being loaded (with WP_UnitTestCase I'd pull it in in the bootstrap file).

If I cheat and try to define the functions right before the MyTestClass class the tests run but I get the following error:

There was 1 error:

1) MyTestClass::test_uses_get_post
Mockery\Exception\InvalidCountException: Method get_post(42) from Mockery_0__wp_api should be called
 exactly 1 times but called 0 times.

/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/vendor/mockery/mockery/library/Mockery/CountValidator/Exact.php:37
/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/vendor/mockery/mockery/library/Mockery/Expectation.php:271
/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/vendor/mockery/mockery/library/Mockery/ExpectationDirector.php:120
/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/vendor/mockery/mockery/library/Mockery/Container.php:297
/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/vendor/mockery/mockery/library/Mockery/Container.php:282
/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/vendor/mockery/mockery/library/Mockery.php:142
/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/vendor/10up/wp_mock/WP_Mock.php:112
/srv/www/baunsu/htdocs/wp-content/plugins/restaurant-connect/tests/test-restaurant-connect.php:27

@johnpbloch can you point me in the right direction? I looked at WP Async Task but it doesn't look like they are doing anything special to pull in their plugin / WordPress files. I assume this is done by WP_Mock? Can you point me to where?

@johnpbloch
Copy link
Contributor

You could try either putting your main plugin file in the composer.json's autoload settings or putting together a simplified bootstrap file that looks like this:

<?php

require_once __DIR__ . '/vendor/autoload.php';

require_once __DIR__ . '/restaurant-connect.php';

@w3guy
Copy link

w3guy commented Dec 10, 2015

I ran into this issue today.

Here is my test method

public function testFunctionToDetermineIfEnqueueIsCalled() {
        \WP_Mock::expectActionAdded( 'wp_enqueue_scripts', array($this->class_instance, 'hosted_fields_css') );

        $this->class_instance->init();
    }

Mind you, i already have $this->class_instance defined in setUp() and am not using WordPress testCase but PHPUnit_Framework_TestCase

Any help please? cc @johnpbloch

@ericmann
Copy link
Collaborator

These issues are all highly related, and can be solved with some more in-depth docs and tutorials. Closing not to say it's an invalid issue. You're all definitely heard here, and we'll ship some more solid documentation in the coming weeks to help move past these issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Reporter Feedback Issue has open questions pending original reporter feedback
Projects
None yet
Development

No branches or pull requests

6 participants