Search code examples
javamockitopowermockito

Unable to mock certain final classes with PowerMockito - java.lang.IllegalAccessError


When I try to mock certain final classes like SearchGoogleAdsRequest from a certain Google library they give me IllegalAccessError , I have added @PrepareForTest annotation on top of the class.

@RunWith(PowerMockRunner.class)
@PrepareForTest({SearchGoogleAdsRequest.class})
@PowerMockIgnore({"javax.net.ssl.*"})
public class GoogleAdsReportDownloaderTest {
final SearchGoogleAdsRequest searchGoogleAdsRequest = PowerMockito.mock(SearchGoogleAdsRequest.class);
final GoogleAdsServiceClient mockGoogleAdsServiceClient = mock(GoogleAdsServiceClient.class);
final GoogleAdsServiceClient.SearchPagedResponse searchPagedResponse =
            mock(GoogleAdsServiceClient.SearchPagedResponse.class);

when(mockGoogleAdsServiceClient.searchPagedCallable()).thenReturn(callable);
when(mockGoogleAdsServiceClient.searchPagedCallable().call(searchGoogleAdsRequest)).thenReturn(searchPagedResponse);
when(searchPagedResponse.iterateAll()).thenReturn(Arrays.asList(mockGoogleAdsRow));
when(mockGoogleAdsServiceClient.search(any())).thenReturn(searchPagedResponse);

    

Error

java.lang.IllegalAccessError: Class com/google/ads/googleads/v6/services/SearchGoogleAdsRequest$MockitoMock$1353664588 illegally accessing "package private" member of class com/google/protobuf/GeneratedMessageV3$UnusedPrivateParameter

SearchGoogleAdsRequest final class looks like this, which PowerMockito isn't able to mock.

public final class SearchGoogleAdsRequest extends GeneratedMessageV3 implements SearchGoogleAdsRequestOrBuilder {

    private static final SearchGoogleAdsRequest DEFAULT_INSTANCE = new SearchGoogleAdsRequest();
    private static final Parser<SearchGoogleAdsRequest> PARSER = new AbstractParser<SearchGoogleAdsRequest>() {
        public SearchGoogleAdsRequest parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException {
            return new SearchGoogleAdsRequest(input, extensionRegistry);
        }
    };

    private SearchGoogleAdsRequest(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
        super(builder);
        this.memoizedIsInitialized = -1;
    }

    private SearchGoogleAdsRequest() {
        this.memoizedIsInitialized = -1;
        this.customerId_ = "";
        this.query_ = "";
        this.pageToken_ = "";
        this.summaryRowSetting_ = 0;
    }

I am able to bypass this , by configuring MockMaker. But MockMaker doesn't work with PowerMockito and gives errors (cannot initialize plugin and that certain loader was supposed to go with Mockito but is loading with PowerMockito).

I need to use Power Mockito because I need to mock local scope objects and other unit tests created by others break with MockMaker.


Solution

  • I resolved this using newBuilder to create an object of the class and bypass the issue. It doesn't really mock the class, but I could use this in my case as an argument to a class which I needed to mock. If we don't require PowerMockito then we can use Mockito along with MockMaker, where these classes can be easily mocked though.

    final SearchGoogleAdsRequest searchGoogleAdsRequest = SearchGoogleAdsRequest.newBuilder().build();
    final GoogleAdsServiceClient mockGoogleAdsServiceClient = mock(GoogleAdsServiceClient.class);
    final GoogleAdsServiceClient.SearchPagedResponse searchPagedResponse =
                mock(GoogleAdsServiceClient.SearchPagedResponse.class);
    
    
    when(mockGoogleAdsServiceClient.searchPagedCallable()).thenReturn(callable);
    when(mockGoogleAdsServiceClient.searchPagedCallable().call(searchGoogleAdsRequest)).thenReturn(searchPagedResponse);
    when(searchPagedResponse.iterateAll()).thenReturn(Arrays.asList(mockGoogleAdsRow));
    when(mockGoogleAdsServiceClient.search(any())).thenReturn(searchPagedResponse);