Agile FAQs
  About   Slides   Home  

 
Managed Chaos
Naresh Jain’s Random Thoughts on Software Development and Adventure Sports
     
`
 
Discovering...
Industrial Logic

Microblog Feed
    Previous Feeds...
    Recent Thoughts

    Recent Comments
    Categories
    Archives
    June 2009
    M T W T F S S
    « May   Jul »
    1234567
    891011121314
    15161718192021
    22232425262728
    2930  
    RSS Feed
    Add to Technorati Favorites

    Communication in Code #1 Priority

    Here is a sample of code (happens to be from a test) which I think is not communicative.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    public class ContactNumberTest {
      final String exampleCountryCode1 = "91";
      final String exampleCountryCode2 = "1";
      final String exampleNumber1 = "8012345678";
      final String exampleNumber2 = "2028569635";
     
      ContactNumber phoneNumberA = new ContactNumber(exampleCountryCode1,exampleNumber1);
      ContactNumber phoneNumberB = new ContactNumber(exampleCountryCode1,exampleNumber1);
      ContactNumber phoneNumberC = new ContactNumber(exampleCountryCode2,exampleNumber2);
     
      @Test
      public void testEquals() {
        //Symmetry
        assertTrue(phoneNumberA.equals(phoneNumberB));
        assertTrue(phoneNumberB.equals(phoneNumberA));
     
        //Reflexivity
        assertTrue(phoneNumberA.equals(phoneNumberA));
     
        //Not equals
        assertFalse(phoneNumberA.equals(phoneNumberC));
      }
     
      @Test
      public void testHashcode() {
        assertTrue(phoneNumberA.hashCode() == phoneNumberB.hashCode());
      }
    }

    I know you must be wondering why in the first place someone is writing tests for equals and hashCode. I agree. Its not required. But lets say someone really needs to.

    This is how I would refactor the code to make it more communicative.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    
    public class ContactNumberTest {
      private final String indiaCountryCode = "+91";
      private final String usCountryCode = "+1";
      private final String cellNumber = "8012345678";
      private final String mobileNumber = "2028569635";
     
      private final ContactNumber indianNumber = new ContactNumber(indiaCountryCode, cellNumber);
      private final ContactNumber sameIndianNumber = new ContactNumber(indiaCountryCode, cellNumber);
      private final ContactNumber usNumber = new ContactNumber(usCountryCode, mobileNumber);
      private final Map<contactnumber , String> users = new HashMap</contactnumber><contactnumber , String>();
      private String userName;
     
      @Test
      public void isSymmetrical() {
        assertNotSame(indianNumber, sameIndianNumber);
        assertEquals(indianNumber, sameIndianNumber);
        assertEquals(sameIndianNumber, indianNumber);
      }
     
      @Test
      public void isReflexive() {
        assertEquals(indianNumber, indianNumber);
      }
     
      @Test
      public void isTransitive() {
        ContactNumber newIndianNumber = new ContactNumber(indiaCountryCode, cellNumber);
        assertEquals(indianNumber, sameIndianNumber);
        assertEquals(sameIndianNumber, newIndianNumber);
        assertEquals(newIndianNumber, indianNumber);
      }
     
      @Test
      public void areNotAlwaysEqual() {
        assertFalse(indianNumber.equals(usNumber));
      }
     
      @Test
      public void equalsIsExceptionFree() {
        assertFalse(indianNumber.equals(null));
      }
     
      @Test
      public void isHashFriendly() {
        addUser("Foo").usingKey(indianNumber);
        assertEquals("Foo", users.get(indianNumber));
        addUser("Bar").usingKey(sameIndianNumber);
        assertEquals(1, users.size());
      }
     
      private void usingKey(final ContactNumber number) {
        users.put(number, userName);
      }
     
      private ContactNumberTest addUser(final String userName) {
        this.userName = userName;
        return this;
      }
    }
    </contactnumber>
    • Share/Bookmark
    • Good suggestions @Amol and @Stephen.

      @Giorgio, in my case, I use a template in my IDE to generate this code. Do you test generated code?

      Also what you are referring to, is usually considered as bullet proofing and when I'm doing TDD I don't try to bullet proof my code. I'm writing tests to drive my design not to bullet proof it.

      As far a documentation goes, I would agree with you in other cases, but in the case of equals() and hashcode(), I would say all my developers should know how it works and how to use it. If they don't, then we have a bigger issue to deal with.
    • Why not testing equals()? If there is logic there (which fields should be confronted and which are ignored) it should be tested to prevent regression. And the tests also provide documentation for how equals() can be used.
    • Stephen Souness
      You could also consider using assertSame in the isHashFriendly code.
    • Nice blog. But, don't you think the assertion
       assertEquals(1, users.keySet().size()); 

      would be more explicit than
       assertEquals(1, users.size()); 


      inside
       @Test isHashFriendly()
      ?
    blog comments powered by Disqus
        Licensed under
    Creative Commons License
    Design by vikivix