0

Consider I have a class Tournament with methods register() and isAlreadyRegistered(). Below is the sample code.

public class Tournament {

    private boolean register(String teamName) {

        if(!isAlreadyRegistered(teamName)) {
    
           // register team
    
           return True;
        }
        return False;
    }
    
    private boolean isAlreadyRegistered(String teamName) {
        // Check if team is already registered, involves DB calls
    }

    public static void main(String[] args) throws Exception {
        Tournament tournament = new Tournament();
        tournament.register("e-LEMON-ators");
    }
}

I have a Java test-case which calls main method of class Tournament, which leads to call to register() method and register() method calls isAlreadyRegistered(). Consider below code:

@Test
public void testTournament() {
    try {
        Tournament.main(args);
        } catch (Exception e) {
            fail();
        }
}

I want to mock isAlreadyRegistered(), maybe using Mockito, so it always returns True

Note: The example is only for demonstration purpose and I cannot modify the Tournament class. Modifications can only be made in Test case. Testing register() separately is not an option (call has to be made through main method)

EDIT: I cannot create object for class Tournament i.e. I can interact with the class only through main() method

3
  • Does this help? stackoverflow.com/questions/37095096/… Commented Dec 8, 2020 at 13:14
  • Thanks @SusanMustafa, but I cannot create object for class Tournament i.e. I can interact with the class only through main() method Commented Dec 8, 2020 at 13:17
  • Then you have basically "super-hard to test code". The real world solution would be to change your production code. But note: you could use PowerMock(ito), that would allow you to "intercept" that call to new Tournament() to return some mocked object (and you could still have a mock that calls real methods where needed). But all of that is dirty dark magic. Dont do it unless you really have no other option. Commented Dec 8, 2020 at 16:05

1 Answer 1

2

Try moving the actual register method call into a different method so that you can pass the instance of tournament to the method. Which means, modify your main method to

public static void main(String[] args) throws Exception {
    Tournament tournament = new Tournament();
    performRegister(tournament);
  }

  public static void performRegister(Tournament tournament) {
    tournament.register("e-LEMON-ators");
  }

Now your test method becomes as below.

@Test
  public void testTournament() {
    try {
      Tournament tournament = Mockito.mock(Tournament.class);
      Mockito.when(tournament.isAlreadyRegistered(anyString())).thenReturn(true);
      Tournament.performRegister(tournament);
    } catch (Exception e) {
      fail();
    }
  }

Edit : Another solution is, If you don't want to modify Tournament class, use PowerMock.

Here is the test class

    import static org.junit.Assert.fail;
    import static org.mockito.Matchers.anyString;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(Tournament.class)
    public class TournamentTest {
    
      @Test
      public void testTournament() {
        try {
          Tournament mock = PowerMockito.mock(Tournament.class);
          PowerMockito.when(mock.isAlreadyRegistered(anyString())).thenReturn(true);
          PowerMockito.whenNew(Tournament.class).withAnyArguments().thenReturn(mock);
          Tournament.main(null);
        } catch (Exception e) {
          fail();
        }
      }
    
    }

Here are the dependencies

    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito</artifactId>
      <version>1.6.4</version>
      <scope>test</scope>
    </dependency>

Here are the files for the reference
Tournament.java : https://gist.github.com/sjabiulla/4bdf71f81079e38aef137e64913bf26b TournamentTest.java : https://gist.github.com/sjabiulla/4a557516e834bba6d6047687f7e32deb pom.xml : https://gist.github.com/sjabiulla/10abb153e82e14194fd1ccc2689b192d

Sign up to request clarification or add additional context in comments.

7 Comments

Hi @i.am.jabi, like I mentioned in my question, I cannot modify Tournament class and your solution would involve adding additional method.
@ShubhamKadam check the edited solution now
Hi @i.am.jabi, I tried your code, it didn't work. I tried printing value returned by isAlreadyRegistered() and it printed false
@ShubhamKadam , I have tested this and provided the solution. It works 100% on my side. Can you tell me what dependencies you have.. In my pom.xml, I only have added the above mentioned PowerMock dependencies and literally nothing else. And I am using Java 8 .
Hi @i.am.jabi, I created a new project and used dependencies mentioned by you, then I made sure isAlreadyRegistered() throws exception (divide by zero) and it did, which caused testcase to fail. Shouldn't PowerMockito prevent that from happening? i.e return true FYI. I am too using java 8 (openJDK)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.