Search code examples
javaeclipseinterfaceassertjjunit3

Can't use assertThat in test case - "The method assertThat(Point) is undefined for the type CleverBrainTest"


I'm taking an entry-level Java course and have run into an issue that is preventing me from submitting an assignment.

I have to use assertThat in my test cases to satisfy the automatic grader's requirement that I write unit tests. The issue is that I am unable to use the method without receiving this error: "The method assertThat(Point) is undefined for the type CleverBrainTest"

In Eclipse, the error shows up as a red lightbulb to the left of every line where I try to use assertThat. The error also shows up in the testing result when I attempt to run the test.

Eclipse suggests that I use assertTrue instead, and this works. However, the automatic grading system for my class rejects it. It will only accept assertThat.

Additional context:

  • The class instructed me to set up my test classes as JUnit 3 tests, which I have done.
  • I'm also supposed to include certain imports at the top of the test class, which I think I have done properly.
  • CleverBrain implements the Brain interface, which is an interface for a bot that automatically plays Tetris based on student-written methods. This is my first time trying to write tests for an interface. I suspect that's why I'm running into issues. I may just not understand how to do this properly.
  • For some reason, when I tried making a setUp() method, it did not work. I instead had to boilerplate all my initial setup for my tests in each method. I have not run into this issue in the past, and I wonder if it has something to do with writing tests for interfaces.
  • I'm using a Ubuntu-based Linux distribution

I'm including my test case titled CleverBrainTest in the post. Please bear with me as I am very new to Java. Any guidance is greatly appreciated, and I can supply more information if needed. I'm very interested in learning why this is happening so I can address similar issues in the future. Below is the code, I'll also include the trace for the error.

// -------------------------------------------------------------------------
import student.*;
import student.tetris.*;
import static org.assertj.core.api.Assertions.*;

/**
 *  Tests to measure performance of CleverBrain
 * 
 *  @author My Name
 *  @version Today's Date
 */
public class CleverBrainTest
    extends TestCase
{
    //~ Fields ................................................................
    
    
    //~ Constructors ..........................................................

    //~Public  Methods ........................................................    
    /**
     * Tests brain's ability to place sticks in deep holes
     */
    public void testStickInDeepHole()
    {
        Board deepHole = new Board(10, 24,
            "######### ",
            "######### ",
            "######### ",
            "######### "
            );
        Brain myBrain = new CleverBrain();
        Piece stick = Piece.getPiece(Piece.STICK, 0);
        Move best = myBrain.bestMove(deepHole, stick, 20);   

        // Now call the brain
        best = myBrain.bestMove(deepHole, stick, 20);

        // Expect the piece will go to the bottom right hole
        this.assertThat(best.getLocation()).isEqualTo(new Point(10, 0));
        // Expect the piece is rotated counter-clockwise 0 times
        this.assertThat(best.getPiece()).isEqualTo(Piece.SQUARE, 0); // make sure it's correct
    }
    
    
    /**
     * Tests Brain's ability to choose a reasonable target
     */
    public void testSetTarget()
    {
        Board squareHole = new Board(10, 24,
            "          ",
            "#####  ###",
            "#####  ###",
            "##########"
            );
        Brain myBrain = new CleverBrain();
        Piece square = Piece.getPiece(Piece.SQUARE, 0);
        Move best = myBrain.bestMove(squareHole, square, 20);

        // Now call the brain
        best = myBrain.bestMove(squareHole, square, 20);
        
        // Expect the lower left destination is where the hole is
        System.out.println(best.getLocation());
        this.assertThat(best.getLocation()).isEqualTo(new Point(5, 1));
    }
}

The trace for the error

java.lang.Error: Unresolved compilation problem: 
    The method assertThat(Point) is undefined for the type CleverBrainTest

    at CleverBrainTest.testSetTarget(CleverBrainTest.java:66)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at junit.framework.TestCase.runTest(TestCase.java:176)
    at junit.framework.TestCase.runBare(TestCase.java:141)
    at junit.framework.TestResult$1.protect(TestResult.java:122)
    at junit.framework.TestResult.runProtected(TestResult.java:142)
    at junit.framework.TestResult.run(TestResult.java:125)
    at junit.framework.TestCase.run(TestCase.java:129)
    at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)


Things I Have Tried

  • Including the jar (or at least what I believe to be the correct jar -- it's called assertj-core-3.19.0.jar) for assertJ in the project's build path. Strangely enough, I haven't needed to do this to get assertions working properly in my previous projects (none of which involved working with interfaces). This did not work. The error persisted.
  • Using JUnit 4. I couldn't get this to work, maybe due to user error. I'm not sure if this is a valid fix anyway because the class instructs me to use JUnit 3. This also did not resolve the error.

Solution

  • In Java, this refers the to the instance of the enclosing class which the method was invoked on. For example, if you have the following:

    public class Person {
    
      private final String name;
    
      public Person(String name) {
        // 'this' is differentiating between the 'name' *field* 
        // and the 'name' *parameter*
        this.name = name;
      }
    
      public void speak() {
        // Note the only 'name' in scope here is the field, so 
        // technically 'this` can be omitted (and typically is)
        System.out.println("Hello, from " + this.name + "!");
      }
    
      public static void main(String[] args) {
        Person p1 = new Person("John");
        Person p2 = new Person("Jane");
    
        p1.speak();
        p2.speak();
      }
    }
    

    You would see the following output:

    Hello, from John!
    Hello, from Jane!
    

    Because:

    • this == p1 for the p1.speak() invocation.

    • this == p2 for the p2.speak() invocation.

    Note that this cannot be used in static contexts (e.g., the main method above) because there is no "current instance" in static contexts.

    By using:

    this.assertThat(best.getLocation()).isEqualTo(new Point(10, 0));
    

    You are explicitly telling Java to invoke an assertThat method on this, where this is an instance of CleverBrainTest in this context. But that class does not have an assertThat method, thus the code fails to compile. The assertThat method comes from AssertJ's Assertions class. It is also a static method, meaning you do not need an instance of Assertions to call it.

    One way to fix this is to import org.assertj.core.api.Assertions and then use:

    Assertions.assertThat(best.getLocation()).isEqualTo(new Point(10, 0));
    

    However, you already have the following import:

    import static org.assertj.core.api.Assertions.*;
    

    That is a static import. Static imports let you reference static members (e.g., methods, enum constants, etc.) without having to prefix them with the class name. That import is also a star import, which means every static member of Assertions is being imported. All that means you can simply do:

    assertThat(best.getLocation()).isEqualTo(new Point(10, 0));
    

    Without the Assertions prefix and it will still work. Though note if CleverBrainTest did have an assertThat method then that method would take precedence over the statically imported assertThat method, so in that case you would have to prefix the method call with Assertions in order to call the correct one.


    Eclipse suggests that I use assertTrue instead, and this works.

    There is no assertTrue method in the code you provided, so I can only assume it comes from the TestCase superclass (which I believe is a JUnit 3 class?).