TDD for Euler Problem #4 I am in the process of learning Java and going through the Euler problems. For Problem 4 I decided to also implement a TDD approach with JUnit.

My questions are:


Is there a better TDD approach to this problem?

I wrote out all these test cases initially. Some obviously pass and some fail initially because I'm checking a boolean. This makes it impossible to write a failing test in this fashion, should I have written only a failing scenario (say test100), then added in more as my method worked?

Being new to Java, are there obvious code organization things I am missing? 
Any naming tips would be appreciated as well as I am terrible at this generally!


I have three source files:

main.java

public class main {

    public static void main(String[] args) {

        PalindromeChecker p = new PalindromeChecker();
        int largest=0;
        int product;

        for (int i = 999; i&gt;100; i--){

            for (int j = 999; j&gt;100; j--){
                product = i*j;
                if (p.isPalindrome(product) &amp;&amp; product &gt; largest) {
                    largest = product;
                }
            }
        }
        System.out.println(largest);
    }
}


PalindromeChecker.java

public class PalindromeChecker {

    public boolean isPalindrome(int input){

        String str = new Integer(input).toString();
        int len = str.length();

        for(int i = 0; i &lt; Math.ceil(len/2.0); i++){

            if (str.charAt(i) != str.charAt(len-i-1)) {
                return false;
            }
        }

        return true;

    }
}


PalindromeCheckerTest.java

import static org.junit.Assert.*;
import org.junit.Test;

public class PalindromeCheckerTest {

    @Test
    public void test10() {
        PalindromeChecker checker = new PalindromeChecker();
        assertFalse("10 failed",checker.isPalindrome(10));
    }
    @Test
    public void test112() {
        PalindromeChecker checker = new PalindromeChecker();
        assertFalse("112 failed",checker.isPalindrome(112));
    }
    @Test
    public void test900() {
        PalindromeChecker checker = new PalindromeChecker();
        assertFalse("900 failed",checker.isPalindrome(900));
    }

    @Test
    public void test1000() {
        PalindromeChecker checker = new PalindromeChecker();
        assertFalse("1000 failed",checker.isPalindrome(1000));
    }


    @Test
    public void test909() {
        PalindromeChecker checker = new PalindromeChecker();
        assertTrue(checker.isPalindrome(909));
    }

    @Test
    public void test1001() {
        PalindromeChecker checker = new PalindromeChecker();
        assertTrue(checker.isPalindrome(1001));
    }

    @Test
    public void test11() {
        PalindromeChecker checker = new PalindromeChecker();
        assertTrue(checker.isPalindrome(11));
    }

    @Test
    public void test111() {
        PalindromeChecker checker = new PalindromeChecker();
        assertTrue(checker.isPalindrome(111));
    }

}
First of all, your PalindromeChecker does not contain any state, it is a simple input --> output operation not depending on outer factors. This makes it an ideal candidate for being a static method.

Your naming is okay overall, but I would use the name Palindromes for your class.



String str = new Integer(input).toString();


It is better to use String.valueOf here. There's no need to create an Integer object.



for (int j = 999; j&gt;100; j--){


Technically, you're off by one here. You're missing the case when j == 100, which is also a three-digit number (the same goes for i btw).

Correct would be (also with improved spacing)

for (int j = 999; j &gt;= 100; j--) {




So, here's how I would make your class:

public class Palindromes {

    public static boolean isPalindrome(int input) {
        String str = String.valueOf(input);
        int len = str.length();

        for(int i = 0; i &lt; Math.ceil(len/2.0); i++) {
            if (str.charAt(i) != str.charAt(len - i - 1)) {
                return false;
            }
        }
        return true;
    }

}




All your test cases contains pretty much the same code, but with different parameters.

With the change to a static method, the test cases will look more like:

assertFalse("10 failed", Palindromes.isPalindrome(10));


This is ideal for a Parameterized test, which will make it significantly easier to add more tests.

@RunWith(Parameterized.class)
public class PalindromeTest {
    @Parameters
    public static Collection&lt;Object[]&gt; data() {
        return Arrays.asList(new Object[][] {     
                 { 10, false },
                 { 100, false },
                 { 909, true },
                 ...
           });
    }

    private final int input;

    private final boolean expectedPalindrome;

    public PalindromeTest(int input, boolean expectedPalindrome) {
        this.input = input;
        this.expectedPalindrome = expectedPalindrome;
    }

    @Test
    public void test() {
        assertEquals("Failed for " + input,
            expectedPalindrome, Palindromes.isPalindrome(input));
    }
}