I have an enum class with an overloaded from
method like so:
//actual implementation has @Service annotation
public interface Service {
enum Level {
NO(0),
YES(1),
SOME(2)
public final Integer value;
Level(Integer value) {
this.value = value;
}
public static Level from(Boolean value) {
return Boolean.TRUE.equals(value) ? YES : NO;
}
public static Level from(Level value) {
return value;
}
}
//I didn't create this, but the reason for the overloaded from is that we're currently using the Boolean version, but will possibly switch that up later so the overload offers some future proofing I presume.
from
is currently only used with this method: public Boolean getLevel()
, therefore it can only return YES
or NO
in reality, however behavior does exist for SOME
that I want to test. However I cannot get that value without mocking from
This behavior is in another class that calls Service.Level.from
with service.getLevel()
:
@Component
public class Impl
private final Service service;
private final OtherClass otherClass;
public void work() {
Service.Level level = Service.Level.from(service.getLevel());
switch (level) {
case YES:
otherClass.someMethod();
break;
case NO:
otherClass.someOtherMethod();
break;
case SOME:
otherClass.thirdMethod();
break;
}
...
}
Here's my test:
@RunWith(MockitoJUnitRunner.class)
public class ImplTest {
@Mock
private Service service;
@Mock
private OtherClass otherClass;
@InjectMocks
private Impl impl;
@Test
public void testYes {
doReturn(Boolean.TRUE).when(service).getLevel();
impl.work();
verify(otherClass).someMethod();
}
@Test
public void testNo {
doReturn(Boolean.FALSE).when(service).getLevel();
impl.work();
verify(otherClass).someOtherMethod();
}
@Test
public void testSome {
doReturn(Boolean.FALSE).when(service).getLevel();
try (MockedStatic<Service.Level> mockedStatic = mockStatic(Service.Level.class)) {
mockedStatic.when(() -> Service.Level.from(any(Boolean.class))
.thenReturn(Service.Level.Full);
}
impl.work();
verify(otherClass).thirdMethod();
}
}
The first two tests pass as expected but the third one doesn't end up mocking from
and returns NO
, which is its unmocked behavior.
I also attempted to make the staticMock class-level:
private static MockedStatic<Service.Level> mockedStatic;
@BeforeClass
public static void beforeClass {
mockedStatic = mockStatic(Service.Level.class);
}
...
then call that with
mockedStatic.when(() -> Service.Level.from(any(Boolean.class)).thenReturn(/*test-appropriate return value here*/);
//example:
@Test
public void testNo {
//
doReturn(Boolean.FALSE).when(service).getLevel();
mockedStatic.when(() -> Service.Level.from(any(Boolean.class)).thenReturn(Service.Level.NO);
impl.work();
verify(otherClass).someOtherMethod();
}
but then I ran into ExceptionInInitializerError
and then NoClassDefFoundError
, the former caused by a NullPointerException
in switch()
in Impl.work()
, however calling Service.Level.from
with a debugger does return the appropriate enum constant, only for the actual method call to then fail. I suspect this might have to do with Service
being mocked and its inner class Service.Level
being static mocked, however the thrown issues do not even hint towards that.
How can I solve this issue?
Apologies that I'm not posting the actual error messages but that would reveal my company and some class names that I'd rather avoid.