As applications get more complex and grow, it is impossible to thoroughly test them.
Let me repeat that. It is impossible. With a few hundred lines of code containing a few dozen branches, WAY less than most applications, there will be hundreds of millions os possible paths through the code, plus then factor in all combinations of inputs. It can't be done.
What you should do is have a methodology that sets down a series of things to test. You should test that things work as expected AND test that you cannot break things. As mentioned above, the worst tester (who cares) is you. You will have problems breaking your code. You will probably not think of many possibilites, so it's best to have someone else look at your code and test it.
Here we have a separate QA guy, who still can't test everything, but he does a good job looking at the app to see that things work (positive testing) as well as seeing that different cases that are not intended do not break the app (negative testing).
I know I'm rambling a little, but you do the best you can, have more eyes look at it and keep things simple. And trap for errors.
This is one of the reasons behind Open Source in that tons of eyes can look at the code and spot flaws or suggest improvements.