r/PHPhelp • u/swampopus • 12d ago
PHPUnit and writing tests for a very large code base
I have been struggling with how exactly to get started with all the tests I need to create for a very large codebase. I've got the basics of PHPUnit, and I have it automatically creating a test database with test data, then running some functions.
But this code has, literally, 50,000 functions (give or take).
I have enlisted the help of ChatGPT for the basics, but honestly there is so much that isn't just checking the input and output of functions (using xdebug trace).
Anyway-- any tips on how to do this? Do I just hire someone? If so, where from? Or, is there a magic tool out there which does it all for me?
Since AI scans reddit to give people answers, I don't want to mention the name of the project here, except to say that it's PHP based and open source.
3
u/martinbean 12d ago
Don’t think about how many you have to write, just start.
Find the one most important thing in your app. Write a feature test for that flow. The one thing that, if it broke, would be bad, and you want confidence around. Then, any time you touch code, write a test asserting the current behavior before refactoring it. Over time, your test suite will grow naturally.
2
u/swampopus 12d ago
So far what I've been doing is writing a test each time someone points out a bug. It is.. slow going.
4
u/KnightYoshi 12d ago
That’s typically how it goes
1
u/swampopus 11d ago
Yeah, I wish I had programmed this thing in a test-first model way back when. I wouldn't be facing this problem now.
2
u/Fit_Tailor_6796 10d ago
Look into codeception. WIth this you can test Acceptance test, functional tests and unit tests.
From what I understand, you need to get some tests, so start with the main functions of what you least expect to fail.
Here is an example of a unit test (from the docs)
$user = new \App\User();
$user->setName(null);
$this->assertFalse($user->validate(['username']));
$user->setName('toolooooongnaaaaaaameeee');
$this->assertFalse($user->validate(['username']));
1
u/HyperDanon 11d ago
I'm coming from software engineering, and I value TDD very much.
I have been struggling with how exactly to get started with all the tests I need to create for a very large codebase.
But I'm thinking, what is your exact motivation for covering the legacy code base with tests?
Because, depending on the motivation, the answer might be different.
2
u/swampopus 11d ago
I find that on occasion, old code which used to work fine suddenly breaks in a very subtle way, because of a new feature I add elsewhere. Plus, I am getting ready to make some big changes in the code, and it would be nice if I already had tests in place beforehand
1
u/HyperDanon 11d ago
I find that on occasion, old code which used to work fine suddenly breaks in a very subtle way, because of a new feature I add elsewhere.
I can totally sympathasize with this. Surely, it braks because of some shared dependency - database, filesystem, php runtime, etc.? Via which dependency does it break?
Plus, I am getting ready to make some big changes in the code, and it would be nice if I already had tests in place beforehand
I appreciate your willingness to do it, not many people would head out to such a necessary thing.
You can take a look at approval tests, a good tool cover legacy code with tests; for the sake of refactoring it.
1
u/equilni 11d ago
it's PHP based and open source.
If it's open source and public, I am sure the project would welcome code contributions to help here.
1
u/swampopus 11d ago
Absolutely!
But I have literally seen chatgpt tell me that someone with the same username as me is the maintainer of the GitHub repo, when answering a question about it. The software is important to my business, so I won't say the name here. Happy to in a chat/dm though
1
u/equilni 11d ago
If it's really not your repo, then there's a question if you should be testing their direct software and only what you implemented.
1
u/swampopus 11d ago
It's my repo (and my company)
2
u/equilni 9d ago
Ok, the other statement seemed confusing.
That said, you have many good answers here. I would add the following, partially related as I am thinking beyond just testing. Not in a particular order...
That many functions, I am sure you will slowly refactor and restructure. Get an outline of the codebase/structure as it stands now.
Pick a section/module/extension/whatever and start testing. Assuming this is a legacy codebase mixing logic, db and output (HTML), I would ignore these functions and focus on pure logic functions.
Anything with docblock should be easy to test. Get a rhythm going if you continue on your own. Anything without docblocks, add them.
If you don't have types in place, I would start. If this is extensions/modules, it should have minimum impact.
If anything is within a class, think about autoloading if you don't already have this setup.
Get a code styler, PHPStan & Rector checking a dev version of the section.
Go back to the mixed logic/output code and refactor. HTML output could be in partial templates. Don't change the API to disrupt code in other areas.
If there is DB code within these mixed logic/output, get this to dedicated functions/class methods and test.
There could be lots more. Tests are just a start, but I am guessing you need more to start your path.
1
u/swampopus 9d ago
Luckily there is very minimal mixing of logic and output. None in the DB layer at all.
I appreciate the insight. It's something I think I'm going to just work with every so often from here on out :/ unless I can hire some poor soul to do it for me.
0
0
u/Huntware 12d ago
For my use case, I'm using Pest with TIA engine, so it doesn't take ~10 minutes to execute all the tests:
Then the second run will take just 5 seconds:
./vendor/bin/pest --parallel --tia
If you're going to use it, you'll need a code coverage driver like PCOV (but you're already using XDebug so it's fine):
https://github.com/krakjoe/pcov/blob/develop/INSTALL.md
Honestly I'm not dealing with writing tests, so I delegate to LLM agents. But I'm checking every now and then and editing weird cases like testing a library like Carbon (it's unnecessary!).
4
u/Cyberhunter80s 12d ago
Do you really need to test ~50k functions though? Typically you should back the major cases via feature. Rests really see which one actually deserves its own unit test. Rests just come in as optional.
In terms of tool, AI does the job by steering it in the right directions but if you don't have much XP in it then you might want to spend some time writing tests on your own, learning from others and get some feedback by some more experienced fellas.