4

I want to do something like:

$I->setExpectedException('Laracasts\Validation\FormValidationException');

In a functional cept. Any chance to do so?

\PHPUnit_Framework_TestCase::setExpectedException('Laracasts\Validation\FormValidationException');

Above code will work in isolation but if I run codecept run, the tests get stuck once the test with the expected exception is complete.

Here's my setup:

YML:

class_name: FunctionalTester
modules:
    enabled: [Filesystem, Db, FunctionalHelper, Laravel4, Asserts]

3 Answers 3

13

I think this is a known problem with the Laravel 4 module for codeception, not sure if it is going to be fixed soon, but in the meantime I created a helper function to test Exceptions:

In the file tests/_support/FunctionalHelper.php add the following method:

public function seeExceptionThrown($exception, $function)
{
    try
    {
        $function();
        return false;
    } catch (Exception $e) {
        if( get_class($e) == $exception ){
            return true;
        }
        return false;
    }
}

You use it in your Cepts like this:

$I = new FunctionalTester($scenario);
$I->assertTrue(
    $I->seeExceptionThrown('Laracasts\Validation\FormValidationException', function() use ($I){
    //All actions that you expect to generate the Exception
    $I->amOnPage('/users/edit/1');
    $I->fillField('name', '');
    $I->click('Update');
}));
Sign up to request clarification or add additional context in comments.

3 Comments

I was disappointed that there was no good way to assert an exception is thrown. I saw in an early blog post they used to have a ->seeExceptionThrown() method but doesn't seem to be available anymore. This did the trick for me!
I have spent 30+ minutes figuring out why does it not work for me when I realised that the Exception is not referenced globally, so I had to change catch (Exception $e) to catch (\Exception $e) - I hope it helps somebody one day...
Note, this solution is not limited to only functionalTester or Laravel. In any codeception usage, this actually will solve the exception thrown test. fix.
1

I extended Minds solution a bit:

public function seeException($callback, $exception = 'Exception', $message = '')
  {
    $function = function () use ($callback, $exception) {
      try {
        $callback();
        return false;
      }
      catch (Exception $e) {
        if (get_class($e) == $exception or get_parent_class($e) == $exception) {
          return true;
        }
        return false;
      }
    };
    $this->assertTrue($function(), $message);
  }

In your cepts you can

$I->seeException('Laracasts\Validation\FormValidationException', function() use ($I){
    //All actions that you expect to generate the Exception
    $I->amOnPage('/users/edit/1');
    $I->fillField('name', '');
    $I->click('Update');
})

This way there is no need for assertTrue outside of the exception test method. You can also leave out the second argument if it is fine for you too know that an exception is thrown. Last you can put an message string as third argument. That way you can make the error more expressive if it fails.

EDIT Pardon, I missed one thing. In FunctionalHelper.php you have to extends the parents _beforeSuite method:

public function _beforeSuite()
  {
    parent::_beforeSuite();
    $this->assert = $this->getModule('Asserts');

  }

EDIT2 Just found out that the test method doesn't work if you implicitly assert that an exception is thrown and php's native exception isn't the appearing exceptions parent because the method only checks first and second exception level. To make the method inspect the whole expection stack you have to use this method

public function assertThrows($callback, $exception = 'Exception', $message = '')
  {
    $function = function () use ($callback, $exception) {
      $getAncestors = function($e) {

        for ($classes[] = $e; $e = get_parent_class ($e); $classes[] = $e);
        return $classes;

      }

      try {
        $callback();
        return false;
      }
      catch (Exception $e) {
        if (get_class($e) == $exception or in_array($e, $getAncestors($e))) {
          return true;
        }
        return false;
      }
    };
    $this->assertTrue($function(), $message);
  }

Comments

0

Another approach:

// prev steps

try {
    $model->methodWichThrowsException();
    throw new \RuntimeException('Must throw ExpectedException');
} catch (\ExpectedException $e) {
    
}

// next steps

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.