Search code examples
javajunitcollectionsjava-8

Modifying source code to pass failing junit test regarding element order in a collection


I have a test class called LibraryTest. The junit test defined in this class is failing. I want to pass the failing junit test by only modifying my source code and without changing anything in the junit test.

I have the class files Book.java

public class Book {

    private int id;
    private final String name;
    private final String description;
    private final Category category;
    public Book(int id, String name, String description, Category category) {
        super();
        this.id = id;
        this.name = name;
        this.description = description;
        this.category = category;
    }
    
    public enum Category {
          CoreJava,
          Electronics,
          Python,
          Hibernate
       }
    
    // getter and setters too are there
}

and Library.java

public class Library {
    private final Set<Book> books = new HashSet<Book>();
    public boolean addBook(final Book book) {
          return books.add(book);
       }
       
       public Iterator<Book> getBooks() {
          return books.iterator();
       }
}

The test class file LibraryTest.java is as follows. The junit test canSortLibrary() is failing.

public class LibraryTest{

   private Library library;
   private Book hibernate1 ;
   private Book hibernate2 ;
   private Book coreJava ;
   private Book electronics ;
   private Book python;

   @Before
   public void setUp() {
     library = new Library();
     hibernate1 = new Book(0, "hibernate1", "hibernate book1", Category.Hibernate);
     hibernate2 = new Book(0, "hibernate2", "hibernate book2", Category.Hibernate);
     coreJava = new Book(0, "coreJava", "written by x", Category.CoreJava);
     electronics = new Book(0, "electronics", "written by y", Category.Electronics);
     python = new Book(0, "Python Book", "written by someone", Category.Python);

     library.addBook(hibernate1);
     library.addBook(hibernate2);
     library.addBook(coreJava);
     library.addBook(electronics);
     library.addBook(python);
   }

  @Test
   public void canSortLibrary() throws Exception {
      final Book[] orderedBooks = new Book[] { coreJava, hibernate1, hibernate2, electronics, python};
      int i = 0;
      final Iterator<Book> books= library.getBooks();
      
      while (books.hasNext()) {
         final Book book = books.next();
         Assert.assertTrue(book == orderedBooks[i++]);
      }
      
   }
}

Solution

  • According your constraints you need to make your Book class comparable in a very particular way.

    Book.java

    import java.util.Arrays;
    
    public class Book implements Comparable<Book> {
        static String specialOrder[] = {"coreJava", "hibernate1", "hibernate2", "electronics", "Python Book"};
    
        private int id;
        private final String name;
        private final String description;
        private final Category category;
        public Book(int id, String name, String description, Category category) {
            super();
            this.id = id;
            this.name = name;
            this.description = description;
            this.category = category;
        }
        
        public enum Category {
            CoreJava, Electronics, Python, Hibernate
        }
    
        @Override
        public int compareTo(Book otherBook) {
            int index = Arrays.asList(specialOrder).indexOf(name);
            int indexOther = Arrays.asList(specialOrder).indexOf(otherBook.getName());
            if (index != -1 && indexOther != -1) {
                // both book titles are in the special order array
                // the indices indicate their order
                return Integer.compare(index, indexOther);
            }
            // at least one book title is not in the special array
            // therefore use natural order of String
            return name.compareTo(otherBook.getName());
        }
    
        // getter and setters too are there
        String getName(){return name;}
    }
    

    And use a container which maintains the order:

    Library.java

    import java.util.*;
    public class Library {
        private final SortedSet<Book> books = new TreeSet<Book>();
        public boolean addBook(final Book book) {
              return books.add(book);
           }
           
           public Iterator<Book> getBooks() {
              return books.iterator();
           }
    }
    

    Now we are set and here we go:

    $ javac Book.java Library.java 
    $ javac -cp .:junit-4.13.2.jar LibraryTest.java                                          
    $ java -cp .:junit-4.13.2.jar:hamcrest-all-1.3.jar org.junit.runner.JUnitCore LibraryTest
    JUnit version 4.13.2
    .
    Time: 0,003
    
    OK (1 test)
    
    $