I am currently reading a book about testing with testNG and Mockito in order to refine my skills of using that tools, widen my knowledge about testing in general and improve the quality of code I create.
After the 4th chapter, "Test Driven Development" there are plenty of exercises I should do to harden what I have just learnt about TDD and to get a habit of the cycle Red Test -> Implement code -> Green Test -> Refactor. One of them is called "PasswordValidator", which should, well, validate strength of a password.
One of recommended approaches to such development is to start with the easiest possible test and incrementally, by writing more complicated test cases, implement more complex functionality. Truth be told, normally I would solve that problem by writing a proper regex ( like for instance this one: https://stackoverflow.com/a/5142164/2576122), write a few tests that will cover whatever border cases I might imagine and be done with that.
And here, I go with firstly creating PasswordValidatorTest class and in it tests such as:
@Test
public void returnsTrueWhenPasswordIsAtLeastEightCharsLong() {
assertTrue(atLeastEightCharactersLong(EIGHT_CHARACTERS_LONG_PASSWORD));
}
I check that it fails, implement logic in PasswordValidator:
public static boolean atLeastEightCharactersLong(String passwordToValidate) {
if (passwordToValidate.length() >= 8) {
return true;
} else {
return false;
}
}
I check that it is green, then I refactor:
public static boolean atLeastEightCharactersLong(String passwordToValidate) {
return (passwordToValidate.length() >= 8);
}
The same goes with tests for containing digits, special signs etc. At some point of such procedure, I end up with a final test:
@Test
public void shouldReturnTrueIfPasswordIsValid() {
assertTrue(PasswordValidator.isValid(VALID_PASSWORD_EXAMPLE));
}
For which implementation is:
public static boolean isValid(String passwordToValidate) {
return atLeastEightCharactersLong(passwordToValidate) && containsAtLeastTwoDigits(passwordToValidate) &&
containsAtLeastOneSpecialSign(passwordToValidate);
}
And then after tests is green I can clearly see, that all earlier tested methods should be, from the very beginning, private ones.
Does it often happen, and is it accepted, that during coding some tests in TDD, that were at first useful, are removed? Because one thing for certain - these methods should not be exposed at all to that class user, so answer such as "make them protected" don't appeal to me.
Or maybe my approach from the very beginning is invalid and I should have only written a test for isValid() method, to test behaviour of an API? If I did so such test would be too general though and wouldn't allow me to check all border cases while development, or maybe I got it all wrong? Is there a line between what to test and what should not be tested at all? What should be the granularity?