12

My target is to mock Build.Version.SDK_INT with Mockito. Already tried:

final Build.VERSION buildVersion = Mockito.mock(Build.VERSION.class); doReturn(buildVersion.getClass()).when(buildVersion).getClass(); doReturn(16).when(buildVersion.SDK_INT); 

Problem is that: when requires method after mock, and .SDK_INT is not a method.

2
  • stackoverflow.com/questions/38074224/… Commented Oct 28, 2016 at 10:33
  • Perhaps don't..? It seems like you're trying to mock too hard. If you're trying to get code coverage for the line of code which reads that int, then why? If you're trying to get the system to show it behaves differently with different builds, then wrap the call to Build behind something you CAN mock. Commented Oct 28, 2016 at 21:33

3 Answers 3

20

So far from other questions similar to this one it looks like you have to use reflection.

Stub value of Build.VERSION.SDK_INT in Local Unit Test

How to mock a static final variable using JUnit, EasyMock or PowerMock

static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } 

...and then in this case use it like this...

setFinalStatic(Build.VERSION.class.getField("SDK_INT"), 16); 

Another way around would be to create a class that accesses/wraps the field in a method that can be later mocked

public interface BuildVersionAccessor { int getSDK_INT(); } 

and then mocking that class/interface

BuildVersionAccessor buildVersion = mock(BuildVersionAccessor.class); when(buildVersion.getSDK_INT()).thenReturn(16); 
Sign up to request clarification or add additional context in comments.

3 Comments

Superb - It is much cleaner solution
This no longer works in my code - I am getting java.lang.NoSuchFieldException: modifiers and my tests are all failing.
6

This works for me while using PowerMockito.

Whitebox.setInternalState(Build.VERSION.class, "SDK_INT", 16); 

Don't forget to type

@PrepareForTest({Build.VERSION.class}) 

Comments

0

In case of java.lang.ExceptionInInitializerError , use 'SuppressStaticInitializationFor' to suppress any static blocks in the class. Usable example as follows:

@SuppressStaticInitializationFor({ "android.os.Build$VERSION", "SampleClassName" )} 

Be careful inner class must use $ instead of Dot .

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.