Quick Testing Tips: Testing Anything; Better Than Testing Nothing? – Matthias Noback

“Yes, I know. Our tests aren’t perfect, but it’s better to test anything than to test nothing at all, right?”

Let’s look into that for a bit. We’ll try the “Fowler Heuristic” first:

One of my favourite (of the many) things I learned from consulting with Martin Fowler is that he would often ask “Compared to what?”

  • Agile helps you ship faster!
  • Compared to what?

[…]

Often there is no baseline.

Daniel Terhorst-North

The baseline here is: no tests. The statement is that having some kind of test is better than having no tests. Without any context, this is evidently true. Since we know that tests are good, and we want tests for our code, but we have no tests yet, adding some kind of test gets us at least one step closer to the end goal.

However, without context, most statements can’t be judged for their value. So let’s add some context. My guess is that most development teams want tests for their code for two reasons:

  1. They want to have the tests form a kind of safety net, for when they’re making changes to that horrible legacy code.
  2. They want to understand why something was implemented the way it is by reading the tests.

To judge the value of any test over no test we should find out if those few tests that developers write in a #NoTest code base are actually helpful to achieve 1 and 2.

UI Tests

Another common minimal approach to testing is to go The Framework Way. Whatever the framework describes in their “Testing” chapter, the team will do. Mostly this results in tests that focus around performing web UI interactions and checking what ends up being in the database afterwards. These tests also break for all kinds of unrelated reasons, which makes them annoying to maintain. They are usually quite slow. This reduces the value of the safety net they provide. Furthermore, in most cases they still don’t document the “why”. They show a number of steps and what’s supposed to happen, but they don’t explain why that happens in this case. There is often no clear connection between the start and the end of the test.

Based on my experience with different teams and different projects, this leads me to think that it’s definitely not better to write any test than no test. If you don’t know what types of test you should write for each area of your application, you’ll end up with an unmaintainable test suite, and demotivating team standards like “every class should have a test”. If anything, you’ll get people to dislike writing tests. At that point, your principle that “any test is better than no test” has reached the opposite of the intended effect.

Good Tests

Instead of writing just any test, focus on writing good tests. Work on tests together, treat them as specifications (which makes it easier to include the “why”, something we programmers often forget). While doing so, make sure that writing tests is Fun, Easy, and Effective. The FEE for this is that you have to invest in:

  • Test tools that help you run specific tests really quickly (Can you right-click a specific test method and run it in PhpStorm? You should!)
  • Tests that give quick results (How long does it take to run the relevant tests before committing? If it’s more than a few seconds, fix it!)
  • It should be really cheap to add more test cases to show how the code behaves when different data is being provided (How much do you have to copy/paste when you want to create a new test class, or a new test method? Make sure it’s just a few lines).

This approach, I claim, is Effective; when the test suite no longer works against you, it’ll become a trusted safety net instead of an annoying maintenance burden. More tests will be created, and they will be of a better quality than just one-class-one-test or make-request-then-look-in-DB tests.

Test Debt

I’m sure it takes a lot of effort, but just like everybody understands Technical Debt for production code and invests in improving its design, you know you have Test Debt; both in your own experience as a developer and in your project. So, go go go!

Ep#361 – Interview with Dana Luther – Voices of the ElePHPant

Listen as host Khayrattee Wasseem talks with Dana Luther about her two talks for Longhorn PHP happening in Oct 2021 – docker secrets & exakat using docker.

She explains how she participated in the “School the World” movement to help children in poor countries. She also talks about her passion for singing.

This episode is sponsored by
RingCentral Developers

The post Ep#361 – Interview with Dana Luther appeared first on Voices of the ElePHPant.

Xdebug Update: August 2021 – Derick Rethans

Xdebug Update: August 2021

In this monthly update I explain what happened with Xdebug development in this past month. These will be published on the first Tuesday after the 5th of each month.

Patreon and GitHub supporters will get it earlier, around the first of each month.

You can become a patron or support me through GitHub Sponsors. I am currently 58% towards my $2,000 per month goal. If you are leading a team or company, then it is also possible to support Xdebug through a subscription.

In August, I worked on Xdebug for about 50 hours, with funding being around 25 hours, which is only half.

Xdebug Videos

I have published two more videos on how to use Xdebug on my YouTube channel.

These are part of a series to explain how to use Xdebug:

  • Xdebug 3 Profiling: 3. Analysing Data, where I show how to use KCacheGrind to read and analyse profiling files to find bottlenecks in code.

  • Xdebug 3: Activation and Triggers, where I explain how to activate Xdebug’s myriad of features with different methods, including cookies, GET/POST parameters, environment variables, and with a browser extension.

I will create more videos in the upcoming month, and if you would like to suggest a topic for a 5 to 10 minute long video, feel free to request them through this Google Form.

PHP on the road to the 8.1.0 release – Remi Collet

Version 8.1.0 Release Candidate 1 is released. It’s now enter the stabilisation phase for the developers, and the test phase for the users.

RPM are available in the remi-php81 repository for Fedora  33 and Enterprise Linux  7 (RHEL, CentOS), or in the php:remi-8.1 stream, and as Software Collection in the remi-safe repository (or remi for Fedora)

 

emblem-important-4-24.pngThe repository provides development versions which are not suitable for production usage.

Also read: PHP 8.1 as Software Collection

emblem-notice-24.pngInstallation : read the Repository configuration and choose installation mode.

Replacement of default PHP by version 8.1 installation, module way (simplest way on Fedora and EL-8):

dnf module reset php
dnf module install php:remi-8.1
dnf update

Replacement of default PHP by version 8.1 installation, repository way (simplest way on EL-7):

yum-config-manager --enable remi-php81
yum update php\*

Parallel installation of version 8.1 as Software Collection (recommended for tests):

yum install php81

emblem-important-2-24.pngTo be noticed :

  • EL8 rpm are build using RHEL-8.4
  • EL7 rpm are build using RHEL-7.9
  • lot of extensions are also available, see the PHP extension RPM status page and PHP version 8.1 tracker
  • follow the comments on this page for update until final version
  • should be proposed for Fedora 36

emblem-notice-24.pngInformation, read:

Base packages (php)

Software Collections (php81)

PHP 8.1.0 RC 1 available for testing – PHP: Hypertext Preprocessor

The PHP team is pleased to announce the release of PHP 8.1.0, RC 1. This is the first release candidate, continuing the PHP 8.1 release cycle, the rough outline of which is specified in the PHP Wiki. For source downloads of PHP 8.1.0, RC 1 please visit the download page. Please carefully test this version and report any issues found in the bug reporting system. Please DO NOT use this version in production, it is an early test version. For more information on the new features and other changes, you can read the NEWS file or the UPGRADING file for a complete list of upgrading notes. These files can also be found in the release archive. The next release will be the second release candidate (RC 2), planned for 16 September 2021. The signatures for the release can be found in the manifest or on the QA site. Thank you for helping us make PHP better.

Advanced PHPUnit shenanigans – Larry Garfield

Advanced PHPUnit shenanigans

In my last post, we talked about PHPUnit’s data providers, and how to leverage them to write more maintainable tests. Today, I want to talk about two more test-writing techniques that I’ve found to be very helpful.

Continue reading this post on PeakD.

Larry
1 September 2021 – 11:27am

Quick Testing Tips: Self-Contained Tests – Matthias Noback

Whenever I read a test method I want to understand it without having to jump around in the test class (or worse, in dependencies). If I want to know more, I should be able to “click” on one of the method calls and find out more.

I’ll explain later why I want this, but first I’ll show you how to get to this point.

As an example, here is a test I encountered recently:

public function testGetUsernameById(): void
{ $userRepository = $this->createUserRepository(); $username = $userRepository->getUsernameById(1); self::assertSame('alice', $username);
}

The way I read this:

/* * Ah, we're testing the UserRepository, so we instantiate it. * The factory method probably injects a connection to the test * database or something: */
$userRepository = $this->createUserRepository(); /* * Now we fetch a username by its ID. The ID is 1. That's the * first time I see it in this test. This probably means that * there is no user with this ID and the method will throw * an exception or return a default name or something: */
$username = $userRepository->getUsernameById(1); /* * Wait, the username is supposed to be "alice"? * Where did that come from? */
self::assertSame('alice', $username);

So while trying to understand this test that last line surprised me. Where does Alice come from?

As it turns out there is a setupTables() function which is called during the setup phase. This method populates the database with some user data that is used in various ways by one of the test methods in the class.

private function setupTables(): void
{ $this->connection->table('users') ->insert( [ ['user_id' => 1, 'username' => 'alice', 'password' => 'alicepassword'], ['user_id' => 2, 'username' => 'bob', 'password' => 'bobpassword'], ['user_id' => 3, 'username' => 'john', 'password' => 'johnpassword'], ['user_id' => 4, 'username' => 'peter', 'password' => 'peterpassword'], ] ); // ...
}

There are some problems with this approach:

  • It’s not clear which tests rely on which database records (a common issue with shared database fixtures). So it’s hard to change or remove tests, or the test data, when needed. As an example, if we remove one test, maybe some test data could also be removed but we don’t really know. If we change some test data, one of the tests may break.
  • It’s not clear which of the values is actually relevant. For example, we’re interested in user 1, 'alice', but is the password relevant? Most likely not.

The first thing we need to do is ensure that each test only creates the database records that it really needs, e.g.

public function testGetUsernameById(): void
{ $this->connection->table('users') ->insert( [ 'user_id' => 1, 'username' => 'alice', 'password' => 'alicepassword' ] ); $userRepository = $this->createUserRepository(); $username = $userRepository->getUsernameById(1); self::assertSame('alice', $username);
}

At this point the test is already much easier to understand on its own. You can clearly see where the number 1 and the string 'alice' come from. There’s only that 'alicepassword' string that is irrelevant for this test. Leaving it out gives us an SQL constraint error. But we can still get rid of it here by extracting a method for creating a user record, moving the insert() out of sight:

public function testGetUsernameById(): void
{ $this->createUser(1, 'alice'); $userRepository = $this->createUserRepository(); $username = $userRepository->getUsernameById(1); self::assertSame('alice', $username);
} private function createUser(int $id, string $username): void
{ $this->connection->table('users') ->insert( [ 'user_id' => $id, 'username' => $username, 'password' => 'a-password' ] );
}

Going back to the beginning of this post:

  • When I read a test method I want to understand it without having to jump around in the test class (or worse, in dependencies).
  • If I want to know more, I should be able to “click” on one of the method calls and find out more.

With just a few simple refactoring steps we’ve been able to achieve these things. As a consequence we achieve th

Truncated by Planet PHP, read more at the original (another 1692 bytes)

PHP Internals News: Episode 94: Unwrap Reference After Foreach – Derick Rethans

PHP Internals News: Episode 94: Unwrap Reference After Foreach

In this episode of “PHP Internals News” I chat with Nikita Popov (Twitter, GitHub, Website) about the “First Class Callable Syntax” RFC.

The RSS feed for this podcast is https://derickrethans.nl/feed-phpinternalsnews.xml, you can download this episode’s MP3 file, and it’s available on Spotify and iTunes. There is a dedicated website: https://phpinternals.news

Transcript

Derick Rethans 0:14

Hi, I’m Derick. Welcome to PHP internals news, the podcast dedicated to explaining the latest developments in the PHP language. This is Episode 94. Today I’m talking with Nikita Popov about the unwrap reference after foreach RFC that he’s proposing. Nikita, would you please introduce yourself?

Nikita Popov 0:33

Hi, Derick. I’m Nikita and I work at JetBrains on PHP core development.

Derick Rethans 0:38

So no changes compared to the last time.

Nikita Popov 0:41

Yes, at the time before that.

Derick Rethans 0:43

So what is the problem that is RFC is going to solve?

Nikita Popov 0:46

Well, it’s really a very minor thing. I think it’s a relatively well known problem for the more experienced PHP programmers. It’s like a classic example, you have a foreach loop by reference. So foreach array as value by reference, and then you do a second loop after that, foreach array as value at the same it’s by value. So without the reference sign. The result of that is that your last two array elements are going to be the same, which is kind of unexpected. If you’re not familiar with how references in PHP work and scoping in PHP works. So I think it’s worth explaining what’s going on there.

Derick Rethans 1:27

Can you quickly explain the scoping or rather the lack of it, I suppose?

Nikita Popov 1:31

Yeah, it’s really the lack of PHP really only has function scoping. So if you have a foreach array as value, then the value variable is going to stay alive, even after the foreach loop. And usually, that won’t make much of a difference. So you will just have like reference to the last element of the array, might even be useful for some cases, you know, before we added the array, I think, array_key_last function. If the last element now is a reference, so if you have a reference to the last element, then you’re write into that variable is also going to modify the last element of the array. So if you now have a second foreach loop, using the same variable, that’s actually not just modifying that variable, but it’s also always modifying the last element of the array.

Derick Rethans 2:15

Okay, just to clarify, it isn’t necessarily the last element in the foreach loop. It’s the last one that’s been assigned to?

Nikita Popov 2:22

Yeah, that’s, that’s true.

Derick Rethans 2:24

Is this not something that people actually use for some useful reasons?

Nikita Popov 2:28

As mentioned before, technically, you could use it to get a reference to the last element and then modify the last element outside the foreach loop. I don’t think this is a particularly common use case. But I’m sure people have used in here there. This is a use case we would break with the proposed RFC.

Derick Rethans 2:47

I think it is one I have used in the past,

Truncated by Planet PHP, read more at the original (another 14677 bytes)

Fun with PHPUnit Data Providers – Larry Garfield

Fun with PHPUnit Data Providers

Most PHP developers are familiar with PHPUnit these days. It is the most widely used testing framework for PHP by a wide margin (although others do exist). One of its more under-utilized features, though is data providers.

Data providers are a PHPUnit feature (and many testing frameworks have an equivalent) that lets you run a single test method multiple times but with different data. Often it’s presented as a way to save typing, but I find it is also a useful architectural tool, too. And there are ways to use them that are even nicer than what most people tend to do.

Continue reading this post on PeakD.

Larry
24 August 2021 – 12:13pm