In Typescript or other dynamic languages, here's what you need to do to mock a single method on an instance of a class:
const instance = new MyClass()
instance.myMethod = () => getMockResult()
Usually test frameworks provide a helper to do this kind of thing for you, but it's easily accomplished with no magic, using built-in language features.
In nominally-typed languages with static type systems, it's more difficult to alter the behavior of specific instances of classes at runtime. Instead, convention is to declare an interface that specifies some set of methods, and then declare a class that implements the interface. Instead of using a concrete type in business logic, you use the interface type instead. Then, in your tests you can use a different class that also implements the interface:
The "duality" I'm referring to is that in this pattern, every type needs to be defined twice, first as an interface, and then as an implementation.
As other commenters said, there are tools like Mockito that eliminate the need for this double-definition, and enable the same easy re-definition of method behavior at runtime. My point wasn't that is is impossible in Java or other static languages, just that one of the strengths of a more dynamic language is that flexible runtime behavior alteration is ~2 lines of code, versus the 39769 lines of code in eg Java's Mockito.
In nominally-typed languages with static type systems, it's more difficult to alter the behavior of specific instances of classes at runtime. Instead, convention is to declare an interface that specifies some set of methods, and then declare a class that implements the interface. Instead of using a concrete type in business logic, you use the interface type instead. Then, in your tests you can use a different class that also implements the interface:
The "duality" I'm referring to is that in this pattern, every type needs to be defined twice, first as an interface, and then as an implementation.As other commenters said, there are tools like Mockito that eliminate the need for this double-definition, and enable the same easy re-definition of method behavior at runtime. My point wasn't that is is impossible in Java or other static languages, just that one of the strengths of a more dynamic language is that flexible runtime behavior alteration is ~2 lines of code, versus the 39769 lines of code in eg Java's Mockito.