PHPUnit: how to use assertions outside of the "test..." methods? - phpunit

I have the following code:
private function registerShutdownFunction(): void
{
register_shutdown_function(function () {
$this->dropDatabasesAndUsersIfExist();
});
}
And this code:
private function dropDatabasesAndUsersIfExist(): void
{
// some code for deletion of the databases...
foreach ($connections as $connection) {
$this->assertNotContains($connection, $databases);
}
}
But dropDatabasesAndUsersIfExist is not a "test..." method. And phpunit ignores assertions outside of the test methods.
And seems there are problems may occur, because this shutdown function running directly before the die of the script...

You can use PHPUnit's Assert class outside of test cases if that is really what you want to do:
PHPUnit\Framework\Assert::assertNotContains($connection, $databases);
Edit: After reading your question one more time I'm not really sure if my answer helps you. If I got you right, you are already using the assertion but it did not behave as you'd expect it. My guess is that you want the whole test run to fail if any of the assertions in dropDatabasesAndUsersIfExist was not met.
One solution could be to move the checks you are doing in dropDatabasesAndUsersIfExist to a separate test class that should be executed last. You can achieve this by appending another test suite with the new class right after your test suite(s).

Related

An example (or several) about method at() in phpunit

Would anybody, please, show me an example for at method in phpunit test doubles. I don't understand what is its purpose?
The purpose of the at() function is to specify the order that methods on a mock should be called. If you were to use once() or exactly(), the test would pass no matter which order the methods were called as PHPUnit is only checking that they are called during the test not when.
For example:
class FooTest extends PHPUnitTestCase {
public function testProperOrderOfMethods() {
$mockObject = $this->getMockBuilder('BarObject')
->setMethods(['baz', 'boz'])
->getMock();
$mockObject->expects($this->at(0))
->method('boz');
$mockObject->expects($this->at(1))
->method('bar');
$sut = new Foo();
$sut->methodBeingTested($mockObject);
}
This requires that our function needs to look like:
public function methodBeingTested($dependecy) {
$dependency->boz();
$dependency->bar();
}
And would fail if the function order were changed.
An example use case might be your class is using an object that connects to a service and retrieves data. You would want to have the connection opened, retrieve the data, and then close the connection. Or it may need to make further requests depending on the response. Either way all of these actions need to happen in a specific order so in your test, you would use at().

Mockery false positive in Laravel controller test

I'm trying to learn how to use Mockery with Laravel 5. I've based my efforts mostly on Way's book (Laravel Testing Decoded) and other tutorials, which say integration [with PHPUnit] only requires the tearDown() method. So I've included that. The problem is that it doesn't seem to be resetting things between tests. My test class contents look essentially like this:
public function __construct()
{
$this->mock = Mockery::mock('Class\To\Mock');
}
public function tearDown()
{
Mockery::close();
}
public function test_RedirectWithoutAuthentication()
{
// Act
$this->call('GET', '/path/1');
// Assert
$this->assertRedirectedTo('/auth/login');
}
public function test_X()
{
// Arrange
$this->mock->shouldReceive('MockedClassMethod')->once();
// Act
$this->call('GET', '/path/1');
}
The first test works and the Auth middleware kicks the user to the login page. In the interest of TDD, I've written the second test before the MockedClassMethod is actually written. So to my way of thinking, it should fail spectacularly. But it doesn't. It passes!
If I change the order of the tests, it "works" (unwritten fails, auth passes) which leads me to believe that it's not really an order problem, but something to do with one test not getting cleaned up before the next.
Any insights will save my remaining hair from being pulled out. :-)
In accordion with the PHPUnit doc:
The setUp() and tearDown() template methods are run once for each test
method (and on fresh instances) of the test case class.
The constructor is called only the first time so the tearDown is called before the second test executed of the class and the effect is that the mockery instance was closed.
In order to solve your problem you can use the setup method for init the mocked object. So replace the class constructor of the test class with the setup method as follow:
Try to use this:
protected function setUp()
{
$this->mock = Mockery::mock('Class\To\Mock');
}
instead of:
public function __construct()
{
$this->mock = Mockery::mock('Class\To\Mock');
}
Hope this help
I had tried using the setUp() method as described by Matteo, and it caused the tests not to run at all. So I abandoned that course thinking I was way off. But Matteo's suggestion turned me back to it.
A little digging into why it caused the tests to fail showed that the $app object was never getting created. Hmm... So then it dawned on me that the setUp() method was overriding some important stuff. So to fix it, all that was needed was to call the parent method first! Like so:
public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock('Class\To\Mock');
}
From that point, the setUp() and tearDown() worked as expected.
I'm still not sure why all the examples I seem to find show the mock being created in the constructor. Maybe I'm still not getting something, but at least it's working... for now. :-)

AspectJ - Why cflow leads to an infinite recursion when it is not combined with an && (aspectJ intersection)?

I have a question about cflow or cflowbelow in AspectJ.
cflow(Pointcut)
Picks out all join points in the control flow of the
join points picked out by the pointcut, including pointcut's join
points themselves.
cflowbelow(Pointcut)
Picks out all join points in the control flow
below the join points picked out by the pointcut.
For both, I could find only the definition and that:
When defining pointcut using cflow or cflowbelow, we need to ensure
that the pointcut does not capture the calls that are made from the
same aspect, otherwise it will invoke recursive method calls and we
will get StackOverflowError.
This happens because cflow() will also
capture the method calls from the aspect itself and try to apply the
advice to it. This can be avoided by using within() construct.
within() takes a type(class or interface) name as argument and
captures all join points the are defined in that type.
But no explanation about how actually cflow() or cflowbelow() lead to an infinite recursion when they are used without within or together with an && expression like:
pointcut aPointcut(): execution(void Test.foo()) && !cflowbelow(execution(void Test.foo()));
Which will match e.g. the first execution of Test.foo() only ignoring any bubbling if inside Test.foo() another call to Test.foo() is made or a call to a foo() method of a class which extends Test is made.
My question is: why cflow actually leads to an infinite recursion when it is used e.g. without within? How does the weaving with cflow happens so that it leads to such a recursion?
A simple example:
Driver application:
package de.scrum_master.app;
public class Application {
public static void sayHelloTo(String name) {
System.out.println("Hello " + name + "!");
}
public static void main(String[] args) {
sayHelloTo("world");
}
}
Aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Application;
public aspect CflowRecursionDemo {
// Attention, StackOverflowError!
/*
before() : cflow(execution(* Application.sayHelloTo(..))) {
System.out.println(thisJoinPoint);
}
*/
before() : !within(CflowRecursionDemo) && cflow(execution(* Application.sayHelloTo(..))) {
System.out.println(thisJoinPoint);
}
}
The commented-out advice leads to a StackOverflowError while the active one does not.
Console output:
execution(void de.scrum_master.app.Application.sayHelloTo(String))
get(PrintStream java.lang.System.out)
call(java.lang.StringBuilder(String))
call(StringBuilder java.lang.StringBuilder.append(String))
call(StringBuilder java.lang.StringBuilder.append(String))
call(String java.lang.StringBuilder.toString())
call(void java.io.PrintStream.println(String))
Hello world!
Explanation: As you can see there are a number of joinpoints within the control flow of the active advice. Each one of these would again trigger the active advice because each of them again matches the pointcut cflow(execution(* Application.sayHelloTo(..))). The advice is a method like any other, though, it just happens to be inside of an aspect. Anyway, it is in the control flow of its own pointcut which again triggers the advice which again is in its own pointcut's control flow and so forth. Infinite recursion!

How To Ensure an #Test Method Always Runs Before Any Others Regardless of Class, Suite or Group?

My reading of the TestNG docs suggests that if I have a test method marked like this:
#BeforeSuite(alwaysRun = true)
#Test
public void MyTestMethod { ... }
then MyTestMethod would run before any other test defined anywhere, regardless of class, suite or group. But that does not seem to be the case.
Is there a way to make a test method run unconditionally before everything else? (And that if it fails no other tests will be run.)
Edit:
The test class:
class Suite_Setup
extends BaseTestSuite
{
#BeforeSuite(alwaysRun = true)
def setup() {
System.out.println("Conducting test suite setup...")
// Verify that the internal API is configured properly and that the API host is available...
new Action(ApiHostname, new BasicCookieStore)
}
}
Edit:
The answer:
We generate our own TestNG.xml files (automatically) and the #BeforeSuite method was not being included in it. Once it was included, #BeforeSuite had the expected effect.
However, it does appear that both #BeforeSuite (and presumably other #Before... and #After... annotations) can be mixed with #Test and rather than inhibiting the execution of the annotated method, they cause it to run more than once!
Also, I remiss in not indicating which version of TestNG I'm using. It's 6.2.
Try using groups either on class level or on method level.
In my case, I have a set of smoke tests that need to run before everything and if any of those fail, no other tests should run.
#Test(groups="smoke")
public class SmokeTests {
public void test1 {
//
}
...
}
And all other classes with tests are:
#Test(dependsOnGroups = "smoke")
public class OtherTests {
public void test1 {
//
}
...
}
I think that the answer is
to separate the configuration-methods from the test-methods,
to use #BeforeSuite for the method to be executed befor all tests in the suite (for example to get an EntityManager)
to use dependsOnMethods to decide in which order the tests shall be run
In the following example the testRemove will run after testInsert, testReadAll and testUpdate have run.
testReadAll will run after testInsert has run.
testUpdate will run after testInsert has run.
Note that there is no dependency between testReadAll and testUpdate.
#Test
public void testInsert()
{..}
#Test(dependsOnMethods={"testInsert"})
public void testUpdate()
{..}
#Test(dependsOnMethods={"testInsert"})`
public void testReadAll()`
{..}
#Test(dependsOnMethods={"testInsert", "testUpdate", "testReadAll"})`
public void testRemove()`
{..}
Remove #Test, a method cannot be both a configuration and a test method.
#Test (alwaysRun=True)
makes the test always run irrespective of methods or groups it depends on and even it is failed
Is there a way to mark a test method so it will unconditionally be run before everything else?
Just try to assign to target test the lowest priority value.
#Test(priority = -2147483648)
public void myTest() {
...
}
You can read more about TestNG test priority over there.
And that if it fails no other tests will be run.
You need to make other tests depending on this test method by using one of the following options:
Assign to your first method some group and mark other tests by dependsOnGroup.
Mark other tests by dependsOnMethod.
If you will use one of the dependency options you do not need to provide priority for your first method.

FlexUnit and callLater

I'm trying to use callLater with FlexUnit v0.9:
public function testCallLater():void {
Application.application.callLater( addAsync(function():void {
assertTrue(true);
}, 1000));
}
but when it runs I get this error:
ArgumentError: Error #1063: Argument count mismatch on flexunit.framework::AsyncTestHelper/handleEvent(). Expected 1, got 0.
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.core::UIComponent/callLaterDispatcher2()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8628]
at mx.core::UIComponent/callLaterDispatcher()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\UIComponent.as:8568]
I'm not sure what the problem is. Is callLater incompatible with FlexUnit?
First, you should really consider migrating to FlexUnit 4.0: http://blogs.digitalprimates.net/codeSlinger/index.cfm/2009/5/3/FlexUnit-4-in-360-seconds
Second, callLater is meant to be used to delay processing until the next frame in visual classes. Your test case class is not a visual class extending UIComponent, therefore you should not try to use callLater.
Third, addAsync is use to test the results of an asynchronous operation. This is typically used in testing the results of a network request, of a file read, of a timer event, etc. That is why normally you see an "event" as a parameter in the addAsync test function (because asynchronous requests use events to process results). In your case, you're not responding to an asynchronous operation with your addAsync call, and therefore you shouldn't be looking for an event in your test function. Remove the event:Event parameter and the error will go away.
However, perhaps you can re-phrase this question to state what you're trying to accomplish? The code sample that you've indicated is not really doing anything useful. If you can be a little more specific we can help you write a better test case.
For help with using addAsync with older versions of FlexUnit, see this tutorial: http://life.neophi.com/danielr/2007/03/asynchronous_testing_with_flex.html
It looks like you are expecting an event, but not getting one. I imagine the following code would work.
public function testCallLater():void {
Application.application.callLater( addAsync(function(/*removed event declaration*/):void {
assertTrue(true);
}, 1000));
}
Just in case someone needs it, this works :
private function testCallLater():void {
Application.application.callLater(doCallLater, [ addAsync(funcUnderTest, 1000) ]);
}
private function doCallLater(testFunc:Function):void {
testFunc(null); // Dummy arg necessary because of addAsync expecting one arg
}
private function funcUnderTest(e:Object = null):void {
assertTrue(true);
}

Resources