No, it's not false, but I'll rephrase it to illustrate my point: "the only economically practical way to reduce bugs is to test thoroughly, unless you're NASA or you have some magnificent budget that somehow lets you hire people who can mathematically prove your code is bug free".
I am aware that you can prove code is correct, from a math POV. That's about the only way you can write "bug free" code without extensive testing, and even then, I'd argue that's not good enough - code needs to be tested. Bugs don't exist just in code. They exist in CPUs. They exist in configuration. They exist in dependency version mishaps that somehow make your code work incorrectly.
There is no silver bullet here. Sorry - there just isn't.
Type systems are, in essence, automated mathematical theorem provers designed to prevent certain classes of bugs.[1] The functional style is also a bug-reducer in that you can reason more accurately about the state of your program, because you have limited state-changing code to particular places. Certain language features like Lisp's restarts or garbage collection are bug-reducing because they give you concise ways of expressing features you might otherwise have had to implement by hand, and every line of code you write is another line for a bug to hide in.
Yes, testing is invaluable and should not be omitted. No, none of these are silver bullets that eliminate the need for testing. But it is false to say that "...the only economically practical way to reduce bugs is to test thoroughly." There are many ways to reduce bugs that can help alongside testing.
[1]: If you've only ever used C++ or Java, this sounds hilariously weak, but in languages like the ML, the type system prevents null pointer exceptions, and in Haskell, the type system goes further and separates effectful and non-effectful code to ensure you don't cause side effects where you don't expect. Even more powerful are languages like ATS, which give you compile-time type errors when you've forgotten to allocate space for a null terminator for strings.
I think what you mean is "any efficient engineering process will make good use of testing".
But if you already have some tests in place, the most efficient way to reduce bugs is often something other than more testing, e.g. code review, design review/improvements, or static analysis (often provided by the language/compiler).
All of those other methods can and will reduce bugs. So your statement that testing is the only way is obviously false in both a practical and theoretical sense.
> They exist in CPUs. They exist in configuration. They exist in dependency version mishaps [...]
They exist in software assisting with formal methods usage too, but what's worse is that frequently implementation is sound and the program still works incorrectly because of erroneous assumptions or bugs in specification. So no, you cannot be sure that your program is bug free without running it... I'm not sure if it is possible to get to being 100% correct in reality - what with cosmic rays altering memory and such...
I am aware that you can prove code is correct, from a math POV. That's about the only way you can write "bug free" code without extensive testing, and even then, I'd argue that's not good enough - code needs to be tested. Bugs don't exist just in code. They exist in CPUs. They exist in configuration. They exist in dependency version mishaps that somehow make your code work incorrectly.
There is no silver bullet here. Sorry - there just isn't.