Codeception/PHPUnit Assert::isTrue pass with false - codeception

How come the following test pass, does this make sense?
<?php
use \Codeception\Util\Debug;
use \PHPUnit\Framework\Assert;
class TrackingCest
{
// tests
public function tryToTest(AcceptanceTester $I)
{
Debug::debug("I am really here!");
Assert::isTrue(false);
}
}

enricog is right, you need to use
$I->assertTrue(false);
But you will need to enable the Asserts module in your configuration, in acceptance.suite.yml:
classname: AcceptanceTester
modules:
enabled:
- Asserts
Besides that, there is no need to use the use statements at the top.
Your test could look like this:
<?php
class TrackingCest
{
// tests
public function tryToTest(AcceptanceTester $I)
{
codecept_debug("I am really here!");
$I->assertTrue(false);
}
}

You are actually not checking anything.
See implementation of PHPUnits Assert::isTrue method, it only returns a new IsTrue instance:
PHPUnit::Assert
To check for true with codeception you should use the methods on the injected Tester:
$I->assertTrue(false);

Related

How to capture a screenshot with PHPUnit and Selenium2 when the test fails?

I'm using PHPUnit 4.6 and PHPUnit Selenium 1.4.2 with PhantomJS. I want capture a screenshot with the last page when selenium test fails.
In PHPUnit Manual there is a example for Selenium 1, but I'm trying use with Selenium 2, because I need use GhostDriver.
WebTestCase.php
class WebTestCase extends PHPUnit_Extensions_Selenium2TestCase
{
protected $captureScreenshotOnFailure = TRUE;
protected $screenshotPath = '/../../screenshots';
protected $screenshotUrl = 'http://localhost:8080/screenshots';
protected function setUp() {
$this->setBrowser('phantomjs');
$this->setBrowserUrl("http://localhost:8080");
$this->setHost('localhost');
}
}
Test.php
class Test extends WebTestCase
{
public function testTitle()
{
$this->url('');
assertEquals($this->title(), "My App");
}
}
But this not capture a screenshot.
$ vendor/bin/phpunit
PHPUnit 4.6-ge85198b by Sebastian Bergmann and contributors.
Configuration read from /MyApp/phpunit.xml
F
Time: 231 ms, Memory: 5.50Mb
There was 1 failure:
1) Test::testTitle
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-''
+'My App'
/MyApp/tests/functional/Test.php:7
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
Hmm. The difference between SeleniumTestCase and Selenium2TestCase is not really good documented in the PHPUnit Manual. Also there is no clear separation and not enough usage examples for common cases on Selenium2.
$captureScreenshotOnFailure does not exist on
PHPUnit_Extensions_Selenium2TestCase.
Anyway, let's try putting this together:
<?php
class Test extends PHPUnit_Extensions_Selenium2TestCase
{
protected function setUp() {
$this->setBrowser('phantomjs');
$this->setBrowserUrl("http://localhost:8080");
$this->setHost('localhost');
}
public function testEnterText()
{
$this->url("/");
try {
$this->assertEquals($this->title(), "My App");
} catch (Exception $e) {
$this->screenshot( __DIR__.'/'.$this->getName().'-'.time(). '.png');
}
}
public function screenshot($file)
{
$filedata = $this->currentScreenshot();
file_put_contents($file, $filedata);
}
}
The try-catch-block: in the try part the assertion is done, if the assertion fails, the exception is caught. The catch-block gives us a chance to (grab details of the exception or re-throw it or) make a screenshot.
The main function is $this->currentScreenshot(), which was used in this test
https://github.com/giorgiosironi/phpunit-selenium/blob/master/Tests/Selenium2TestCaseTest.php#L733
ScreenshotListener
Please note that there is a ScreenshotListener around, which might be worth looking at:
https://github.com/giorgiosironi/phpunit-selenium/blob/master/PHPUnit/Extensions/Selenium2TestCase/ScreenshotListener.php
With usage example over at https://github.com/giorgiosironi/phpunit-selenium/blob/master/Tests/Selenium2TestCase/ScreenshotListenerTest.php
This might be a cleaner implementation to grab test failures and make shots.
Combining the solutions from #Jens A. Koch and #John Joseph, we get this:
<?php
class homepageTest extends PHPUnit_Extensions_Selenium2TestCase {
private $listener;
public function setUp() {
// Your screenshots will be saved in '/var/www/vhosts/screenshots/'
$screenshots_dir = '/var/www/vhosts/screenshots/';
$this->listener = new PHPUnit_Extensions_Selenium2TestCase_ScreenshotListener($screenshots_dir);
$this->setBrowser('firefox');
$this->setBrowserUrl('https://netbeans.org');
}
public function testNetbeansContainsHorses() {
$this->url('https://netbeans.org');
$this->assertContains('Equestrian', $this->title()); // Will fail on NetBeans page.
}
public function onNotSuccessfulTest($e) {
$this->listener->addError($this, $e, microtime(true));
parent::onNotSuccessfulTest($e);
}
}
A way of doing this across all your web tests is to override one of the test failure functions from the parent test case class, and capture your screenshot there.
Example:
class MyBaseWebTests
{
$this->directory = '/some_path_to_put_screenshots_in/';
// Override PHPUnit_Extensions_Selenium2TestCase::onNotSuccessfulTest
public function onNotSuccessfulTest(Exception $e)
{
$filedata = $this->currentScreenshot();
$file = $this->directory . get_class($this) . '.png';
file_put_contents($file, $filedata);
parent::onNotSuccessfulTest($e);
}
}
Now, after any of your web tests fail, they will dump a screenshot in that folder with the name of the web test class as the filename.
Use this to save screenshot..very useful in case of headless browser.
$fp = fopen('path/35.png', 'wb');
fwrite($fp, $this->currentScreenshot());
fclose($fp);
sleep(1);

Authentication test running strange

I've just tried to write a simple test for Auth:
use Mockery as m;
...
public function testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome() {
$auth = m::mock('Illuminate\Auth\AuthManager');
$auth->shouldReceive('guest')->once()->andReturn(true);
$this->call('GET', '/');
$this->assertRedirectedToRoute('general.welcome');
}
public function testHomeWhenUserIsAuthenticatedThenRedirectToDashboard() {
$auth = m::mock('Illuminate\Auth\AuthManager');
$auth->shouldReceive('guest')->once()->andReturn(false);
$this->call('GET', '/');
$this->assertRedirectedToRoute('dashboard.overview');
}
This is the code:
public function getHome() {
if(Auth::guest()) {
return Redirect::route('general.welcome');
}
return Redirect::route('dashboard.overview');
}
When I run, I've got the following error:
EF.....
Time: 265 ms, Memory: 13.00Mb
There was 1 error:
1) PagesControllerTest::testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome
Mockery\Exception\InvalidCountException: Method guest() from Mockery_0_Illuminate_Auth_AuthManager should be called
exactly 1 times but called 0 times.
—
There was 1 failure:
1) PagesControllerTest::testHomeWhenUserIsAuthenticatedThenRedirectToDashboard
Failed asserting that two strings are equal.
--- Expected
+++ Actual
## ##
-'http://localhost/dashboard/overview'
+'http://localhost/welcome'
My questions are:
Two similar test cases but why the error output differs? First one the mock Auth::guest() is not called while the second one seems to be called.
On the second test case, why does it fail?
Is there any way to write better tests for my code above? Or even better code to test.
Above test cases, I use Mockery to mock the AuthManager, but if I use the facade Auth::shoudReceive()->once()->andReturn(), then it works eventually. Is there any different between Mockery and Auth::mock facade here?
Thanks.
You're actually mocking a new instance of the Illuminate\Auth\AuthManager and not accessing the Auth facade that is being utilized by your function getHome(). Ergo, your mock instance will never get called. (Standard disclaimer that none of the following code is tested.)
Try this:
public function testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome() {
Auth::shouldReceive('guest')->once()->andReturn(true);
$this->call('GET', '/');
$this->assertRedirectedToRoute('general.welcome');
}
public function testHomeWhenUserIsAuthenticatedThenRedirectToDashboard() {
Auth::shouldReceive('guest')->once()->andReturn(false);
$this->call('GET', '/');
$this->assertRedirectedToRoute('dashboard.overview');
}
If you check out Illuminate\Support\Facades\Facade, you'll see that it takes care of mocking for you. If you really wanted to do it the way that you were doing it (creating an instance of mock instance of Auth), you'd have to somehow inject it into the code under test. I believe that it could be done with something like this assuming that you extend from the TestCase class provided by laravel:
public function testHomeWhenUserIsNotAuthenticatedThenRedirectToWelcome() {
$this->app['auth'] = $auth = m::mock('Illuminate\Auth\AuthManager');
// above line will swap out the 'auth' facade with your facade.
$auth->shouldReceive('guest')->once()->andReturn(true);
$this->call('GET', '/');
$this->assertRedirectedToRoute('general.welcome');
}

codeception assertTrue() equivalent?

I've gone through the documentation several times, and through the source, and it doesn't work.
I'm looking for the Codeception equivalent of PHPUnit's "this->assertTrue($var)".
According to the documentation, just like that is should work, but it doesn't, "undefined method". Which helper, module or whatever do I have to activate?
Did you enabled the module 'asserts' in the corresponding suite.yml file? Like:
class_name: UnitTester
modules:
enabled: [Asserts, UnitHelper]
Here is what I wrote in the tests/_helpers/WebHelper.php
(note: WebHelper must be enabled in the .yml)
class WebHelper extends \Codeception\Module {
/**
* #param bool $a
*/
function seeTrue( $a ) {
$this->assertTrue( $a );
}
}
Then, I ran
php codecept.phar build
And now I can write
$I->seeTrue(true);
You just call
\PHPUnit_Framework_Assert::assertTrue (...);

Execute some action when Spock test fails

I'd like to execute some action when Spock test fails. Specifically, take a screenshot. Is it possible? How to do it?
Create a listener class
class ExampleListener extends AbstractRunListener {
def void error(ErrorInfo error) {
println "Actual on error logic"
}
}
then add it to each specification using implementation of IGlobalExtension that is executed for each Spec
class GlobalSpecExtension implements IGlobalExtension {
#Override
void visitSpec(SpecInfo specInfo) {
specInfo.addListener(new ExampleListener())
}
}
and finally create file named org.spockframework.runtime.extension.IGlobalExtension in your META-INF/services directory (typically it will be under src/test/resources if you are using Maven) with the full name of your IGlobalExtension implementation e.g.
com.example.tests.GlobalSpecExtension
The best way to achieve this is to write a (global or annotation-driven) Spock extension that implements and registers an AbstractRunListener. For an example, see OptimizeRunOrderExtension. For how to register a global extension, see the IGlobalExtension descriptor.
There isn't much documentation on extensions because the APIs are still subject to change. If you want to play it safe (and can live with some restrictions), you can implement a JUnit Rule instead.
One problem that you may encounter in both cases is that they don't provide access to the current spec instance. If you need this, you may have to use both an AbstractRunListener (to be notified of the failure) and an IMethodInterceptor (to get hold of the spec instance), both registered by the same extension. (Shouldn't be this hard, but that's what's currently there.)
I've managed to do it this way:
class ExampleTest extends GebSpec{
static boolean success = false
def setup(){
success = false
}
def cleanup(){
assert success == true, someAction()
}
def someAction(){
}
def "TestCase"(){
expect:
/*What you expect here*/
(success = true) != null
}
}
Before each test case "success" is set to false by the setup() method.
At the end of each test case you add the "(success = true) != null" statement. Therefore "success" will only be true if the test case has passed.
After each test case the cleanup() method will verify if "success" is true. If it isn't the method someAction() will be called.
I can't upvote or comment on user3074543's answer, but it's simpler than creating an extension. I want easy. So I shortened user*'s a little (I don't mean the 1-line methods). You can make the logic simpler by recording failure instead of success, and reduce typing with a done() helper.
class Test extends spock.lang.Specification {
def fail
def setup(){ fail = true }
def done(){ !(fail = false) }
def cleanup(){ fail && doStuffWhenFail() }
def 'test things'(){
expect:
stuff
done()
}
}

Yii trace - proper usage

Unit testing and xdebug usage aside, I wish to have a way to throw some browser message is a value is not expected to be present.
Let's say: $className = 45;
If we have:
public function setMainClass($className) {
if (is_string($className)) {
$this->_mainClass = $className;
} else {
echo Yii::trace(CVarDumper::dumpAsString($className),'vardump');
}
}
We will get this output to the browser on development stage.
It's great.
I'm not sure however, if this is a proper way of use Yii::trace of if I'm miss using it.
Please advice.
It is not necessary to echo the call Yii::trace() (it returns void so the echo does nothing). The other recommendation is that you might consider changing category to resemble a path alias as discussed in the documentation. For example-
} else {
Yii::trace(CVarDumper::dumpAsString($className), 'application.models.MyGreatModel');
}