If you force your types to only ever interact with primitives at certain boundaries of your app, you can test for the "what if it's not an integer" stuff at the boundaries only. I.e. the core APIs never see a magic string, an integer, or any other such untyped thing.
In reality, there are always times where that falls a little flat, which is where IMO Gradual Typing comes into its own. The "core", with some assumptions about the boundaries, be statically analysed. You can add your times(int n) method safe in the knowledge that you'll get a runtime error if someone messes up the dynamic type or doesn't run the analyser.
Ultimately, as I want to run all my code before I put into to production, a lack of runtime errors from my tests tells me my code is correct for the situations I designed it to handle. Now if someone comes along later and manages to invoke a state that I hadn't considered, well... all bets are off.