Am I doing it is right? If not what exactly I have to change
It's hard to say just from that short description, but I suspect that, no, you are not doing it right. Note: I am not saying that what you are doing doesn't work or is in some way bad, but you are not doing TDD. The middle "D" means "Driven", the tests drive everything, the development process, the code, the design, the architecture, everything.
The tests tell you what to write, when to write it, what to write next, when to stop writing. They tell you the design and the architecture. (Design and architecture emerge from the code through refactoring.) TDD is not about testing. It isn't even about writing tests first: TDD is about letting the tests drive you, writing them first is just a necessary prerequisite for that.
It doesn't matter whether you actually write the code down, or have it fully fleshed out: you are writing (skeletons of) code in your head, then writing tests for that code. That's not TDD.
Letting go of that habit is hard. Really, really hard. It seems to be especially hard for experienced programmers.
Keith Braithwaite has created an exercise he calls TDD As If You Meant It. It consists of a set of rules (based on Uncle Bob Martin's Three Rules of TDD, but much stricter) that you must strictly follow and that are designed to steer you towards applying TDD more rigorously. It works best with pair programming (so that your pair can make sure you are not breaking the rules) and an instructor.
The rules are:
- Write exactly one new test, the smallest test you can that seems to point in the direction of a solution
- See it fail; compilation failures count as failures
- Make the test from (1) pass by writing the least implementation code you can in the test method.
- Refactor to remove duplication, and otherwise as required to improve the design. Be strict about using these moves:
- you want a new method—wait until refactoring time, then … create new (non-test) methods by doing one of these, and in no other way:
- preferred: do Extract Method on implementation code created as per (3) to create a new method in the test class, or
- if you must: move implementation code as per (3) into an existing implementation method
- you want a new class—wait until refactoring time, then … create non-test classes to provide a destination for a Move Method and for no other reason
- populate implementation classes with methods by doing Move Method, and no other way
Typically, this will lead to very different designs than the oft-practiced "pseudo-TDD method" of "imagining in your head what the design should be, then writing tests to force that design, implement the design you had already envisioned before writing your tests".
When a group of people implement something like a tic tac toe game using pseudo-TDD, they typically end up with very similar designs involving some kind of a Board
class with a 3×3 array of Integer
s. And at least a portion of the programmers will actually have written this class without tests for it because they "know that they're gonna need it" or "need something to write their tests against". However, when you force that same group to apply TDD As If You Meant It, they will often end up with a wide diversity of very different designs, often not employing anything even remotely similar to a Board
.
Is there any way you can identify whether test you have written are enough?
When they cover all the business requirements. Tests are an encoding of the system requirements.
Is it good practice to writing test for very simple functionality which might be equivalent to 1+1 = 2 or is it just an overplay?
Again, you have it backwards: you don't write tests for functionality. You write functionality for tests. If the functionality to get the test to pass turns out to be trivial, that's great! You just fulfilled a system requirement and didn't even have to work hard for it!
Is it good to change functionality and accordingly test if requirement changes?
No. The other way round. If a requirement changes, you change the test which corresponds to that requirement, watch it fail, then change code to make it pass. The tests always come first.
It is hard to do this. You need dozens, maybe hundreds of hours of deliberate practice in order to build up some sort of "muscle memory" to get to a point, where when the deadline looms and you are under pressure, you don't even have to think about it, and doing this becomes the fastest and most natural way to work.