Encoding to interfaces provides many advantages; better testability is one side effect associated with the main advantage: to untie an object from its dependencies .
Say I have a class A, and in its implementation it uses class B. If you do not provide an interface for B, then you tightly linked the design of A and B together (you cannot consider A without this specific implementation of B, since it uses a specific implementation).
If you write interface B (let's say IB) and use it in instead of directly using B, you separate the design and make them independent. A can now function independently of a specific implementation of B, it only knows the interface to it (IB) and the methods that it needs to run on it. Therefore, if you later decide that your implementation of B was not good, or if you want to be able to work on two different IBs depending on the context, you can replace B with B2 , which also implements IB , so you do not need to change it at all A.
The action to create A by injecting an implementation of IB at runtime is as follows:
A myA = new A(new B()); // this could also be new A(new B2()); or anythign else that implements IB
called dependency injection and is the best way to achieve a very desirable OO programming function: control inversion (this is not A, it controls the behavior of its dependencies more, it is an independent class - factory - which controls what is introduced in A).
For the purpose of testing, you can run a unit test A without assuming B (which, obviously, needs to be tested separately). Therefore, in your tests, you can inject a stub or a mock implementation of B to help you test the behavior you want.
(Sorry, there are no real code examples, as I am a Java developer and not very good with C # syntax)