/* * Copyright (c) 2020 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.mockitoinline; import static junit.framework.TestCase.assertEquals; import static junit.framework.TestCase.assertNull; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.times; import java.util.concurrent.atomic.AtomicReference; import org.junit.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.exceptions.base.MockitoException; import org.mockito.exceptions.verification.NoInteractionsWanted; import org.mockito.exceptions.verification.WantedButNotInvoked; public final class StaticMockTest { @Test public void testStaticMockSimple() { assertEquals("foo", Dummy.foo()); try (MockedStatic ignored = Mockito.mockStatic(Dummy.class)) { assertNull(Dummy.foo()); } assertEquals("foo", Dummy.foo()); } @Test public void testStaticMockWithVerification() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); dummy.verify(Dummy::foo); } } @Test public void testStaticMockWithVerificationFailed() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { assertThatThrownBy( () -> { dummy.verify(Dummy::foo); }) .isInstanceOf(WantedButNotInvoked.class) .hasMessageContaining("there were zero interactions with this mock"); } } @Test public void testStaticMockWithNoInteractions() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); dummy.verifyNoInteractions(); } } @Test public void testStaticMockWithNoInteractionsFailed() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); assertThatThrownBy( () -> { dummy.verifyNoInteractions(); }) .isInstanceOf(NoInteractionsWanted.class) .hasMessageContaining("No interactions wanted here") .hasMessageContaining("above is the only interaction with this mock."); } } @Test public void testStaticMockWithNoMoreInteractions() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); dummy.verify(Dummy::foo); dummy.verifyNoMoreInteractions(); } } @Test public void testStaticMockWithNoMoreInteractionsFailed() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); assertThatThrownBy( () -> { dummy.verifyNoInteractions(); }) .isInstanceOf(NoInteractionsWanted.class) .hasMessageContaining("No interactions wanted here") .hasMessageContaining("above is the only interaction with this mock."); } } @Test public void testStaticMockWithDefaultAnswer() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class, invocation -> "bar")) { assertEquals("bar", Dummy.foo()); dummy.verify(Dummy::foo); } } @Test public void testStaticMockWithRealMethodCall() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenCallRealMethod(); assertEquals("foo", Dummy.foo()); dummy.verify(Dummy::foo); } } @Test public void testStaticMockReset() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); dummy.reset(); assertNull(Dummy.foo()); } } @Test public void testStaticMockClear() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); dummy.clearInvocations(); dummy.verifyNoInteractions(); } } @Test public void testStaticMockDoesNotAffectDifferentThread() throws InterruptedException { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); dummy.verify(Dummy::foo); AtomicReference reference = new AtomicReference<>(); Thread thread = new Thread(() -> reference.set(Dummy.foo())); thread.start(); thread.join(); assertEquals("foo", reference.get()); dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); dummy.verify(Dummy::foo, times(2)); } } @Test public void testStaticMockCanCoexistWithMockInDifferentThread() throws InterruptedException { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); dummy.verify(Dummy::foo); AtomicReference reference = new AtomicReference<>(); Thread thread = new Thread(() -> { try (MockedStatic dummy2 = Mockito.mockStatic(Dummy.class)) { dummy2.when(Dummy::foo).thenReturn("qux"); reference.set(Dummy.foo()); } }); thread.start(); thread.join(); assertEquals("qux", reference.get()); dummy.when(Dummy::foo).thenReturn("bar"); assertEquals("bar", Dummy.foo()); dummy.verify(Dummy::foo, times(2)); } } @Test public void testStaticMockMustBeExclusiveInScopeWithinThread() { assertThatThrownBy( () -> { try ( MockedStatic dummy = Mockito.mockStatic(Dummy.class); MockedStatic duplicate = Mockito.mockStatic(Dummy.class) ) { } }) .isInstanceOf(MockitoException.class) .hasMessageContaining("static mocking is already registered in the current thread"); } @Test public void testStaticMockVoid() { try (MockedStatic dummy = Mockito.mockStatic(Dummy.class)) { Dummy.fooVoid("bar"); assertNull(Dummy.var1); dummy.verify(() -> Dummy.fooVoid("bar")); } Dummy.fooVoid("bar"); assertEquals("bar", Dummy.var1); } @Test public void testStaticMockMustUseValidMatchers() { try (MockedStatic mockedClass = Mockito.mockStatic(Dummy.class)) { assertThatThrownBy( () -> { mockedClass.when(() -> Dummy.fooVoid("foo", any())).thenReturn(null); }) .hasMessageContaining("Invalid use of argument matchers!"); Dummy.fooVoid("foo", "bar"); } } static class Dummy { static String var1 = null; static String foo() { return "foo"; } static void fooVoid(String var2) { var1 = var2; } static void fooVoid(String var2, String var3) { var1 = var2; } } }