how to solve "to create a new mock, the existing mock registration must be deregistered"

Viewed 8134

I am getting the Following Exception when trying to mock a static method:

org.mockito.exceptions.base.MockitoException: For de.msggillardon.system.UserContext, static mocking is already registered in the current thread To create a new mock, the existing static mock registration must be deregistered

For the following Code:

 @ExtendWith(MockitoExtension.class)
// @PrepareForTest(UserContext.class)
public class KonfigurationCopyServiceTest {

  public static final String CONFIGURATION_NAME = "Standard-Konfiguration";

  @Mock
  public TriggeringKonfigurationService triggeringKonfigurationService;
  @Mock
  public ReportKonfigService reportConfigurationService;
  @Mock
  public BuchungsschemaService buchungsschemaService;

  public KonfigurationCopyService copyService;

  @BeforeEach
  public void init() {
    Mockito.mockStatic(UserContext.class);
    Mockito.when(UserContext.getUsername()).thenReturn("superuser");

    copyService = new KonfigurationCopyService(triggeringKonfigurationService,
        reportConfigurationService, buchungsschemaService);
  }

Can anyone help please?

Thank you!

Edit: UserContext.java

package de.msggillardon.system;

/**
 * This class contains the username and IP-address of the logged in user. It is initialized for each
 * session.
 *
 * @author wildp
 */
public class UserContext {

  private static final ThreadLocal<UserContext> userContext = new ThreadLocal<>();

  private final String username;

  private final String clientIPAddress;

  /**
   * Constructor.
   *
   * @param username        Username of the user who is logged in
   * @param clientIPAddress IP Address of the user who is logged in
   */
  public UserContext(String username, String clientIPAddress) {
    this.username = username;
    this.clientIPAddress = clientIPAddress;
  }

  /**
   * Initializes the threadLocal
   *
   * @param userContext
   */
  public static void initialize(UserContext userContext) {
    UserContext.userContext.set(userContext);
  }

  /**
   * Removes the current thread's value for this thread-local variable.
   */
  public static void remove() {
    userContext.remove();
  }

  /**
   * Returns the username of the current thread.
   *
   * @return
   */
  public static String getUsername() {
    return userContext.get().username;
  }

  /**
   * Returns the IP address of the client of the current thread.
   *
   * @return
   */
  public static String getClientIPAddress() {
    return userContext.get().clientIPAddress;
  }

  public static UserContext getThreadLocalUserContext(){
    return userContext.get();
  }
}

NEW EDIT: I once again edited my Code so you can see now, that I am using @ExtendWith(MockitoExtension.lass) to Mock.

Also I found the following tip online: https://javadoc.io/static/org.mockito/mockito-core/3.4.3/org/mockito/MockedStatic.html So it seems like I have to do a MockedStatic.close(); maybe as a @AfterEach But when I am trying it gives me the Exception

Cannot make a static reference to the non-static method close() from the type ScopedMock

Still not working :(

6 Answers

So as I use Junit 5 I couldn't use the @Before Annotation so I replaced the @BeforeEach with @BeforeAll. So I did it as following:

  1. Step: Import
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
  1. Step: Add The @TestInstance(PER_CLASS) Annotation (before your class)

  2. Step: @BeforeAll instead of @BeforeEach

That solved my Problem.

Try changing

@BeforeEach

to @Before

That message tells you: you did setup that static mocking before. Because @BeforeEach will do exactly that: run that init() method before each of your test methods. Change your setup to run the method once, not n times.

This works for me:

  private MockedStatic<UserContext> mockStatic;

  @BeforeEach
  public void beforeEach() {
    mockStatic = Mockito.mockStatic(UserContext.class);
  }

  @AfterEach
  public void afterEach() {
    mockStatic.close();
  }

In my case, there is another class which also call mockStatic() on the same class but doesn't call close(), which affects my current test class.

public class Test2 {
  @AfterEach
  public void afterEach() {
    mockStatic.close();
  }
  ...
}

Do you really mock that object?

  @RunWith(MockitoJUnitRunner.class)
public class ConfigurationCopyServiceTest {
    private UserContext userContext = new UserContext("superUser", "127.0.0.1");
    private ConfigurationCopyService configurationCopyService;
    @Before
    public void setUp() {
        UserContext.initialize(userContext);
        configurationCopyService = new ConfigurationCopyService(triggeringKonfigurationService,
    reportConfigurationService, buchungsschemaService);
    }
    
    @Test
    public void user_name_should_be_same_as_context() {
        assertEquals(UserContext.getUsername(), configurationCopyService.myMethod());
    }
    
}

I was running into the same issue because my class was annotated with

@ExtendWith(MockitoExtension.class)

and

@SpringBootTest

Removing @ExtendWith(MockitoExtension.class) solved the problem for me

Related