Class ClassSanityTester


  • @Beta
    @GwtIncompatible
    public final class ClassSanityTester
    extends Object
    Tester that runs automated sanity tests for any given class. A typical use case is to test static factory classes like:
     interface Book {...}
     public class Books {
       public static Book hardcover(String title) {...}
       public static Book paperback(String title) {...}
     }
     

    And all the created Book instances can be tested with:

     new ClassSanityTester()
         .forAllPublicStaticMethods(Books.class)
         .thatReturn(Book.class)
         .testEquals(); // or testNulls(), testSerializable() etc.
     
    Since:
    14.0
    Author:
    Ben Yu
    • Method Detail

      • testNulls

        public void testNulls​(Class<?> cls)
        Tests that cls properly checks null on all constructor and method parameters that aren't annotated nullable (according to the rules of NullPointerTester). In details:
        • All non-private static methods are checked such that passing null for any parameter that's not annotated nullable should throw NullPointerException.
        • If there is any non-private constructor or non-private static factory method declared by cls, all non-private instance methods will be checked too using the instance created by invoking the constructor or static factory method.
        • If there is any non-private constructor or non-private static factory method declared by cls:
          • Test will fail if default value for a parameter cannot be determined.
          • Test will fail if the factory method returns null so testing instance methods is impossible.
          • Test will fail if the constructor or factory method throws exception.
        • If there is no non-private constructor or non-private static factory method declared by cls, instance methods are skipped for nulls test.
        • Nulls test is not performed on method return values unless the method is a non-private static factory method whose return type is cls or cls's subtype.
      • testEquals

        public void testEquals​(Class<?> cls)
        Tests the Object.equals(java.lang.Object) and Object.hashCode() of cls. In details:
        • The non-private constructor or non-private static factory method with the most parameters is used to construct the sample instances. In case of tie, the candidate constructors or factories are tried one after another until one can be used to construct sample instances.
        • For the constructor or static factory method used to construct instances, it's checked that when equal parameters are passed, the result instance should also be equal; and vice versa.
        • If a non-private constructor or non-private static factory method exists:
          • Test will fail if default value for a parameter cannot be determined.
          • Test will fail if the factory method returns null so testing instance methods is impossible.
          • Test will fail if the constructor or factory method throws exception.
        • If there is no non-private constructor or non-private static factory method declared by cls, no test is performed.
        • Equality test is not performed on method return values unless the method is a non-private static factory method whose return type is cls or cls's subtype.
        • Inequality check is not performed against state mutation methods such as List.add(E), or functional update methods such as Joiner.skipNulls().

        Note that constructors taking a builder object cannot be tested effectively because semantics of builder can be arbitrarily complex. Still, a factory class can be created in the test to facilitate equality testing. For example:

         public class FooTest {
        
           private static class FooFactoryForTest {
             public static Foo create(String a, String b, int c, boolean d) {
               return Foo.builder()
                   .setA(a)
                   .setB(b)
                   .setC(c)
                   .setD(d)
                   .build();
             }
           }
        
           public void testEquals() {
             new ClassSanityTester()
               .forAllPublicStaticMethods(FooFactoryForTest.class)
               .thatReturn(Foo.class)
               .testEquals();
           }
         }
         

        It will test that Foo objects created by the create(a, b, c, d) factory method with equal parameters are equal and vice versa, thus indirectly tests the builder equality.