I think the key here is what you should test.
You mentioned TDD in tags, so I hope we try to stick with this. In this paradigm, the tests you write have two goals:
maintain your code after writing it, so you can reorganize without fear that you broke something.
To guide us to a better way to design components . First, recording a test makes you think about what is needed to solve the problem.
At first I know that this question concerns the first point, but in fact I think about the second. The problem is that you have specific components that you are testing instead of a contract.
In terms of code, this means that I think we should test interfaces instead of class methods, because otherwise we subjected our test to a lot of problems associated with testing components instead of contracts - inheritance strategies, building an object here, renaming.
It is true that interface names will also change, but they will be much tougher than method names. What TDD gives us here is not just a way to support changes with a test harness - it makes it clear that we could be wrong about that!
Take for example the code you gave:
[TestMethod] public void GetCity_TakesParidId_ReturnsParis(){...} {
And let's say we test the GetCity () method on our object, CityObtainer - when did I set this object? Why did I do this? If I understand that GetMatchingCity () is the best name, then you have the problem described above!
The solution I propose is that we think about what this method actually means earlier in this process, using the interfaces:
public interface ICityObtainer { public City GetMatchingCity(); }
Having written this style “outside the home”, we are forced to think about what we want from the object much earlier in the process, and it becomes a focus to reduce its volatility. This does not fix your problem, but can mitigate it a bit (and I think this is the best approach).
Ideally, we take one more step, and before starting the test we do not even write code:
[TestMethod] public void GetCity_TakesParId_ReturnsParis { ICityObtainer cityObtainer = new CityObtainer(); var result = cityObtainer.GetCity("paris"); Assert.That(result.Name, Is.EqualTo("paris"); }
Thus, I can see what I really want from the component, before I even start writing it - if GetCity () is not what I want, but rather GetCityByID () , this would have appeared much earlier in this process. As I said above, it is not reliable, but can slightly reduce pain for this particular case.
As soon as you go through this, I feel that if you change the name of the method, it is because you change the terms of the contract, which means that you must have come back and reviewed the test (since it is possible, you did not want to change it).
(As a quick add, if we are writing a test with TDD, then something happens inside GetCity () , in which significant logic happens. Thinking about the test since concluding the contract helps us to separate the intention from the implementation - the test will remain valid no matter what we will change behind the interface!)