Removed the exception throw for previous and next elements being null, because if the list is a singleton it'll falsely throw an exception.

Replaced the case in insertBefore for e.predecessor()==null and in insertAfter for e.successor()==null with calls to prepend and append respectively, so that the more complete algorithm handles it. This preempts the case where insertAfter is used to start the list.
Formatted the comments
Cast some of the tests as integers to avoid using the toString() function, since we have a separate toString() function we're testing.

Added a test at the bottom to test for a NullPointerException when remove() is called on the last element in the list