Should you change application code to support a test?
Welcome to No Compromises, a peek into the mind of 2 old web devs who have seen some things. This is Joel.
Aaron:And this is Aaron.
Joel:Aaron, we love testing. This is no secret.
Joel:You seem real convinced, but okay.
Joel:But there's something I've seen people do, myself included. All right, I'll throw myself under the bus right away, which is sometimes when you're writing code or when you're writing tests for code that already exists. Right? So let's just say you're coming into a project, there's no tests, or you woke up one morning. You're like, alright.
Joel:Today is the day we're gonna start writing tests on this project. But you bump into the scenario where, oh, man, it would be so much easier to write this test if something about the code changed, like, if this property was public on the job or if something else changed, and I have done that. And you're like, Joel, Joel, don't do that. I thought we might talk about why, because it is something that comes up, and it's not necessarily even a bad impulse, but I think if we step back and talk through why we try not to do it, it could be helpful.
Aaron:Yeah. There's there's 2 different types of code changes, though, that we're talking about here. The first is, changing the architecture of your code to make it more modular, componentized, or whatever like that, smaller pieces, individual things that they can do that make the testing easier because you have some simpler paths to test.
Aaron:So that that's one way which we do support.
Joel:Okay. Good point. Yeah.
Aaron:The way you're talking about is, the setup for my test is pretty complex. The way to measure the effects of this code is pretty complex. Mhmm. So if it wasn't architected in a way that it is, or if it wasn't created in a way it is, I could probably write a bunch of smaller, more precise tests.
Joel:Yeah.
Aaron:But since it isn't, I can still test this, but it's just gonna be a lot of boilerplate work and set up and maybe much slower and everything like that. And I think that's the real reason why people look at some of the code and say, you know, maybe we should change this from a, you know, protected property to a public one because
Joel:Yep.
Aaron:Then I don't have to test the whole life cycle that I've built. I can just kinda focus on individual pieces of data.
Joel:Yeah. And and I'm trying to think of a specific example because there there's one that comes up pretty frequently, and I think it is a Laravel job. Generally, like, if you pass something to the constructor of a job, you probably would just make that a protected property. Right? Like, there's really no reason to make that public because the job is the only thing that needs it.
Aaron:Right.
Joel:But that's a case where the way we like to write tests, feature tests, we might say, oh, this job was dispatched with this property, but you can't do that if it's protected.
Aaron:Right.
Joel:So, like, well, let's just make it public. Like, what does it hurt, Aaron? What does it hurt to just make that public? Come on.
Aaron:Well, that's a whole different discussion. Okay. I I think what we're trying to focus on is Mhmm. Is that tests are a supporting tool
Joel:Yeah.
Aaron:For your code.
Aaron:And so they should be used to make the code better and make it more accurate. And if you've already decided to do a protected property or something like that, that's a like I said, that's a whole other discussion for a different podcast.
Joel:Okay.
Aaron:But chances are, you have a reason from a coding standard, a workflow standard, or whatever that you've done. That means that you've created the code like this in the first place. So since you've done that in the first place, there's a reason. Is writing a test a stronger reason to undo that work? And the answer is is no.
Joel:Yeah. Yeah. You're right. I don't wanna get into the whole public versus protected versus private. I know that sets you off too if we make a bunch of prizes.
Aaron:Set me off. I know I'm right. Okay. Right. Exactly.
Joel:But but the point is, like like, I you because you could even say, well, it doesn't hurt anything. But the point is, like, you didn't do it for a reason, and maybe the reason is just, like, that's the default. Like, when when you build a class, like, why would you make it public unless it needs to be? So, but that's a good point. So let's let's talk a little bit about the, the first thing because I I I sort of skipped over it, which is, like, when when should you change your application code to make a test better?
Joel:And and I because I I wanna dive into that a little bit because I think you you might take away the wrong message if we focus too much on not changing your code, but what what are some good reasons to change your code?
Aaron:Well, I I can look at it as we've been here multiple times, so we know this pain, and and you might too, but this legacy application that we wanna put testing around.
Joel:Mhmm.
Aaron:And so legacy applications might even be built with, like, includes or inline PHP and all this different stuff. So there's a lot more mixed logic in with presentation and all that kind of stuff. And there's a lot of different ways to build up the environment of the request that's gonna go through and and whatnot in these legacy applications. Yeah. So you end up having to say, well, if I wanna test this, it's gonna have to be an end to end test, which again is nicely covering, but it's probable it's more brittle, and it's a lot more work.
Aaron:Right. Yep. And so you have to put this around there. And so when you when you see that, you can start to say, like, okay, does it make sense to maybe, take this API request that's in legacy application and maybe move it to a Laravel app or something like that?
Joel:Right.
Aaron:And then you when you when you start doing that, you start to get more tool sets that can help you change the structure to a little bit more best practices. So you you still might be using, like, just dumping out some JSON. But then after a while, then you start migrating to maybe resources in Laravel or something like that. Yeah. And then and then you can use that as a really good example of, how you can then start writing more focused tests.
Aaron:Is when you start using these tool sets inside of Laravel, you can now start using all their helpers and tools that make your tests easier to write. And you start seeing your productivity and output basically increase when you can write faster tests, when you have better contained code. It just ends up moving faster. Now, if you don't work this way, but just like with every single new thing, it seems like it would take longer until you're good at it. Yeah.
Aaron:And then, you know, just like typing. Right? Like Right. Typing is annoying to learn. But as soon as you know how to type, then you're like, Oh, man.
Aaron:What? And so it's the same sort of thing here. You're gonna start to see that you can start to use tests to build a better architecture of your application and vice versa and and be kind of chicken and egg on each other.
Joel:Yeah. The like, for me, the the differentiation is if you had a time machine, knowing what you know now, would you go back and change this code to be, you know, quote, unquote better? And if the answer is yes, then, like, the test might be the thing that's driving you to do it right now, but it's driving you towards a result you should have already been at. Right? So it's not like the public versus protected property where no.
Joel:Like, you're literally just changing that to make a test a little bit easier. The things you mentioned are, like, just common practices in modern PHP, you know, using a composer auto loader instead of inquire include or require, you know, or just just kinda cleaning up the logic. So, like like, in my mind, that is the big difference. And I'll even give one more example came to my mind that maybe it's not reaching so far back into, like, the old school legacy echo everywhere, you know, days. But even in a relatively newer Laravel app, we've sometimes seen people, for whatever reason, inside a job or somewhere else using new.
Joel:Right? Like, they could have injected something very easily by type, hinting it in the constructor or or whatever method they're using, but they didn't. Right? And and it didn't hurt anything, but it is hard for testing. But I I would also say we're not just changing that to make the test better.
Joel:It actually is improving the design of the app to use dependency injection instead of just, like, newing up something in the middle of a a controller action or or jobs handle method or or something like
Aaron:that. Yeah. It keeps all that code much more composable and small and and more focused, and and that and that's the goal. So
Joel:Yeah. And so just kinda one final thought I wanted to share, because this has come up when I have talked about testing tips like this, is, you kind of avoid these problems if you write your tests to start with. Right? Like, and I'm not talking pure TDD, like, oh, you have to write a failing test before you can write application code. But honestly, some of these design pitfalls you're going to avoid if you just write the tests earlier.
Joel:Now we can't always do it. We can't go back and change, but I think it is an argument for writing tests with application code. It just it sort of keeps you honest and and is a sanity check to the design of your code.
Aaron:Yeah. Test mixed development.
Joel:I like it. This last weekend, my family and I decided to go up north, which in Wisconsin is a thing we do, to enjoy some time away, especially in in the middle of winter, which we're in right now.
Aaron:No. No. No. Let's not say, like, we, as in all Wisconsin people, go up north because no. No.
Aaron:That that's like a southern Wisconsin thing because
Joel:Okay.
Aaron:I grew up up north. And I remember on, like, Fridays Sundays being really annoyed about, like, going to like, you know, onto the highway. Because there was always just a huge line of people from down south where Joel lives No. Coming up north to just destroy all of our pieces of oil.
Joel:No. The people that are the problem are from Chicago, not from Southern Wisconsin. That is absolutely the fact.
Aaron:Wait. Let's throw it down there. That's right. No. No.
Aaron:I I grew up up north, and so I just I can't let Joel get away with these things. It's like it's like when people say, oh, we went up north to go camping. And I'm like, why would you wanna grow up like or why would you wanna, like, go live like I grew up?
Joel:That's right.
Aaron:Yeah. Like, it's it's it's not great. Like, I don't know why you'd wanna do Like, oh, then they complain like, oh, it was really nice. We got to boil the water, but the bugs were bad. Yeah.
Aaron:Imagine the bugs being bad every single day that you tried to go outside.
Joel:Garrett, it's like going to the Renaissance fair. You just want a taste of the hard lifestyle, but you don't wanna have to, like, live in it all the time.
Aaron:Yeah. I don't wanna eat that many turkey legs. Sometimes you kinda maybe feel like on a project, you might have to compromise on the test.
Joel:We don't want that. Head over to nocompromises.io and see how you might work with us, how we could join your project, and help out.