DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Fluent Assertions Reloaded
  • Page Object Model for Performance Testing With Gatling
  • TestCafe Integration With Cucumber
  • AI-Driven Test Automation Techniques for Multimodal Systems

Trending

  • Apache Doris vs Elasticsearch: An In-Depth Comparative Analysis
  • Fraud Detection Using Artificial Intelligence and Machine Learning
  • Java 23 Features: A Deep Dive Into the Newest Enhancements
  • How to Format Articles for DZone
  1. DZone
  2. Coding
  3. Languages
  4. Practical PHP Testing Patterns: Garbage-Collected Teardown

Practical PHP Testing Patterns: Garbage-Collected Teardown

By 
Giorgio Sironi user avatar
Giorgio Sironi
·
Feb. 15, 11 · Interview
Likes (0)
Comment
Save
Tweet
Share
2.6K Views

Join the DZone community and get the full member experience.

Join For Free

In order to perform tests, you create fixtures such as the System Under Test and input or output data. Usually this fixtures are just objects.

Garbage collection, a mechanism present in many languages, deletes objects and variables (and thus fixtures) when there are no references for them anymore in the available scopes.

The logic behind garbage collection is that objects which are not reachable anymore by any other object in the local or global scope are as good as garbage. Their code can't possibly be executed as you cannot call a method on them without a reference.

Basically, if you do not put your fixtures in strange places, they will be automatically deleted with the test case. While a setUp() method is very common, a tearDown() method is usually not necessary.

Implementation

References like local variables or fields on $this (at the Testcase Object level) are deleted with the test case object. Currently, the PHPUnit manual say that the gabage collection of Testcase Objects is not predictable, so you may have to perform an unset() over $this->field to have the object removed.

Static references are special: they are always reachable, as they are kept on classes (the current or other ones) instead of objects, and won't be deleted. Even if an object is pointed by another object in a static reference, it won't be garbage-collected for transitivity.

Also singletons are a big problem (which derives from the static fields where their instances are kept): if you put something in Zend_Registry or in a singleton, it won't be deleted after a test. That's one reason singletons are dangerous: it's not only a matter of performance, but of them being capable of bringing objects from one test to another, spoiling our pursue of test isolation.

PHP garbage collection

Up to PHP 5.2, objects with mutual references won't usually be collected, even if neither of them was reachable from the other scopes. This is not a problem for a script that produces a web page and exits, but it can be for a test suite which runs for some minutes when at full capacity.

In fact, an example of problematic behavior is the ezComponents test suite, which is cited on php.net. The suite would require several gigabytes of memory to run, due to the leaks of the long-running PHP process.

From PHP 5.3, if zend.enable_gc is enabled (by default, it is) cycles will be collected when the table of roots is full. So this particular issue (circular references) won't worry you anymore.

In case you encounter erratic behavior, see if you can change the php.ini directive memory_limit to detect the problem, and use the native function memory_get_usage() to gather statistics.

Examples

In this code sample, I show you tests that create fixtures which are automatically collected. How do we prove that these objects are really deleted? With a simple  __destruct() method.

Keep in mind that explicit teardown is usually not necessary: you should adopt it only if you have an heavy fixture, which you want to be gargabe-collected before the end of the PHP process.

Running this test case:

<?php
class GarbageCollectedTeardownTest extends PHPUnit_Framework_TestCase
{
private $deletedFixture;
private $abandonedFixture;

public function setUp()
{
$this->deletedFixture = new SomeFixture(1);
$this->abandonedFixture = new SomeFixture(2);
}

public function testFirst()
{
}

public function testSecond()
{
}

public function tearDown()
{
// this fixture will be garbage-collected at the end of each test
unset($this->deletedFixture);
// since we do not touch $this->abandonedFixture, its collection
// is not predictable. It can happen at any time after the tests execution.
}
}

class SomeFixture
{
private $number;
public function __construct($number)
{
$this->number = $number;
}

public function __destruct()
{
echo "Cleaning up fixture $this->number.\n";
}
}
gives this output:
[13:11:15][giorgio@Desmond:~]$ phpunit code/practical-php-testing-patterns/GarbageCollectedTeardownTest.php
PHPUnit 3.5.5 by Sebastian Bergmann.

Cleaning up fixture 1.
.Cleaning up fixture 1.
.

Time: 0 seconds, Memory: 4.75Mb

OK (2 tests, 0 assertions)
Cleaning up fixture 2.
Cleaning up fixture 2.
PHP Object (computer science) Testing

Opinions expressed by DZone contributors are their own.

Related

  • Fluent Assertions Reloaded
  • Page Object Model for Performance Testing With Gatling
  • TestCafe Integration With Cucumber
  • AI-Driven Test Automation Techniques for Multimodal Systems

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!