Is a check like isInUnitTest() an antipattern?
Is isInUnitTests() a code smell?
Yes, definitively, you have many ways to avoid coupling your code to unit tests. There is no valid reason to have something like that.
If so, how can I still enforce that unit tests don't reach external dependencies?
Your tests must only validate a unit of code and create mock or stubs for external dependencies.
Your code seems to be Java, which it's plenty of mature mock frameworks. Research a little about existing ones and pick the one that likes you more.
EDIT
how do I prevent a unit test from constructing a real instance of HTTPRequest without putting a check in the constructor / factory method that creates it
You're supposed to use a dependency injector to resolve your instance dependencies so you will never need to use a if
to test if you're on a test or not since on your "real" code you inject full functional dependencies and on your test you inject mock or stubs.
Take a more serious example, like a credit card charger (a classic unit testing example) - it would seem like a very poor design if it were even possible for test code to access the real card charger without triggering a deluge of exceptions. I don't think it's enough in a case like that to trust the developer will always do the right thing
Again, you're supposed to inject external dependencies as a credit card charger so on your test you would inject a fake one. If some developer don't know this, I think the first thing your company needs is training for that developer and some pair programming to guide the process.
In any case, kind of I get your point and let me tell you a similar situation I experienced.
There was an application that sent a bunch of emails after some processing. These emails were not to be send on any other environment except live, otherwise it would be a big problem.
Before I started working on this application, it happened several times that developers "forgot" about this rule and emails were sent on test environments, causing a lot of problems. It's not a good strategy to depends on human memory to avoid this kind of problem.
What we did to avoid this to happen again was adding a config setting to indicate if send real emails or not. The problem was broader than executing things or not on unit tests as you can see.
Nothing replace communication though, a developer could set the incorrect value for this setting on his development environment. You're never 100% safe.
So in short:
- First line of defense is communication and training.
- You second line of defense should be dependency injection.
- If you feel that this is not enough, you could add a third line of defense: a configuration setting to avoid executing real logic on test/development environments. Nothing wrong about that. But please don't name it
IsInUnitTest
as the problem is broader than that (you want also o avoid this logic to be executed on developer machine)