For a university exam i was given to test some of apache bookkeeper classes/methods and in doing so i thought to use mockito in my parameterized test. Test without mockito works fine but when i try to mock an interface i get this error:
org.mockito.exceptions.base.MockitoException: Mockito cannot mock this class: interface org.apache.bookkeeper.discover.RegistrationManager. Mockito can only mock non-private & non-final classes. If you're not sure why you're getting this error, please report to the mailing list. Java : 11 JVM vendor name : Ubuntu JVM vendor version : 11.0.8+10-post-Ubuntu-0ubuntu118.04.1 JVM name : OpenJDK 64-Bit Server VM JVM version : 11.0.8+10-post-Ubuntu-0ubuntu118.04.1 JVM info : mixed mode, sharing OS name : Linux OS version : 4.15.0-112-generic Underlying exception : java.lang.IllegalArgumentException: Could not create type at org.apache.bookkeeper.client.BookKeeperAdminInitNewClusterTest.<init>(BookKeeperAdminInitNewClusterTest.java:40) at org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters.createTestUsingConstructorInjection(BlockJUnit4ClassRunnerWithParameters.java:43) at org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters.createTest(BlockJUnit4ClassRunnerWithParameters.java:38) at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:266) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:27) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) Caused by: java.lang.IllegalArgumentException: Could not create type at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:154) at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:365) at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:174) at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:376) at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:32) at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:71) at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:42) at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25) at org.powermock.api.mockito.mockmaker.PowerMockMaker.createMock(PowerMockMaker.java:41) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35) at org.mockito.internal.MockitoCore.mock(MockitoCore.java:62) at org.mockito.Mockito.mock(Mockito.java:1908) at org.mockito.Mockito.mock(Mockito.java:1817) at org.apache.bookkeeper.client.BookKeeperAdminInitNewClusterTest.<init>(BookKeeperAdminInitNewClusterTest.java:40) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490) ... 26 more Caused by: java.lang.NoSuchMethodError: 'net.bytebuddy.dynamic.loading.MultipleParentClassLoader$Builder net.bytebuddy.dynamic.loading.MultipleParentClassLoader$Builder.appendMostSpecific(java.util.Collection)' at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:83) at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:37) at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:34) at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:152) ... 43 more Here the test class i'm writing:
package org.apache.bookkeeper.client; import org.apache.bookkeeper.conf.ServerConfiguration; import org.apache.bookkeeper.discover.RegistrationManager; import org.apache.bookkeeper.discover.ZKRegistrationManager; import org.apache.bookkeeper.meta.LayoutManager; import org.apache.bookkeeper.test.BookKeeperClusterTestCase; import org.apache.bookkeeper.test.ZooKeeperCluster; import org.apache.bookkeeper.test.ZooKeeperUtil; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.mockito.InjectMocks; import org.mockito.Mock; import java.util.Arrays; import java.util.Collection; import java.util.List; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @RunWith(value= Parameterized.class) public class BookKeeperAdminInitNewClusterTest extends BookKeeperClusterTestCase { private boolean result; private ServerConfiguration conf; private String confType ; private static final int numOfBookies = 2; private final int lostBookieRecoveryDelayInitValue = 1800; @Mock RegistrationManager mockedRM = mock(RegistrationManager.class) ; @Parameterized.Parameters public static Collection<Object[]> getTestParameters(){ return Arrays.asList(new Object[][]{ //last parameter states if the method rm.initNewCluster() called inside // BookKeeperAdmin.initNewCluster(conf) must be mocked or not {true , "new" }, {false , "null" }, {false , "wrong"}, {false , "mock"}, //caso di test introdotto per portare la branch coverage al 100% // entrando nella clausola catch del metodo initNewCluste() }); } public BookKeeperAdminInitNewClusterTest(boolean result , String conf) throws Exception { super(numOfBookies, 480); baseConf.setLostBookieRecoveryDelay(lostBookieRecoveryDelayInitValue); baseConf.setOpenLedgerRereplicationGracePeriod(String.valueOf(30000)); setAutoRecoveryEnabled(true); this.result = result; this.confType = conf; } @Test public void testInitNewCluster() throws Exception { boolean realResult ; if(confType == "null"){ this.conf = null; }else if( confType == "wrong"){ this.conf = new ServerConfiguration().setMetadataServiceUri("zk+hierarchical://127.0.0.1/ledgers"); }else if(confType == "new") { this.conf = new ServerConfiguration(baseConf); String ledgersRootPath = "/testledgers"; this.conf.setMetadataServiceUri(newMetadataServiceUri(ledgersRootPath)); }else if(confType == "mock"){ when(mockedRM.initNewCluster()).thenThrow(new Exception()); } try { realResult = BookKeeperAdmin.initNewCluster(conf); } catch (Exception e) { realResult = false ; e.printStackTrace(); } assertEquals(result,realResult); } } And here the interface i'm trying to mock:
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.bookkeeper.discover; import org.apache.bookkeeper.bookie.BookieException; import org.apache.bookkeeper.common.annotation.InterfaceAudience.LimitedPrivate; import org.apache.bookkeeper.common.annotation.InterfaceStability.Evolving; import org.apache.bookkeeper.versioning.Version; import org.apache.bookkeeper.versioning.Versioned; /** * Registration manager interface, which a bookie server will use to do the registration process. */ @LimitedPrivate @Evolving public interface RegistrationManager extends AutoCloseable { /** * Registration Listener on listening the registration state. */ @FunctionalInterface interface RegistrationListener { /** * Signal when registration is expired. */ void onRegistrationExpired(); } @Override void close(); /** * Return the cluster instance id. * * @return the cluster instance id. */ String getClusterInstanceId() throws BookieException; /** * Registering the bookie server as <i>bookieId</i>. * * @param bookieId bookie id * @param readOnly whether to register it as writable or readonly * @param serviceInfo information about services exposed by the Bookie * @throws BookieException when fail to register a bookie. */ void registerBookie(String bookieId, boolean readOnly, BookieServiceInfo serviceInfo) throws BookieException; /** * Unregistering the bookie server as <i>bookieId</i>. * * @param bookieId bookie id * @param readOnly whether to register it as writable or readonly * @throws BookieException when fail to unregister a bookie. */ void unregisterBookie(String bookieId, boolean readOnly) throws BookieException; /** * Checks if Bookie with the given BookieId is registered as readwrite or * readonly bookie. * * @param bookieId bookie id * @return returns true if a bookie with bookieid is currently registered as * readwrite or readonly bookie. * @throws BookieException */ boolean isBookieRegistered(String bookieId) throws BookieException; /** * Write the cookie data, which will be used for verifying the integrity of the bookie environment. * * @param bookieId bookie id * @param cookieData cookie data * @throws BookieException when fail to write cookie */ void writeCookie(String bookieId, Versioned<byte[]> cookieData) throws BookieException; /** * Read the cookie data, which will be used for verifying the integrity of the bookie environment. * * @param bookieId bookie id * @return versioned cookie data * @throws BookieException when fail to read cookie */ Versioned<byte[]> readCookie(String bookieId) throws BookieException; /** * Remove the cookie data. * * @param bookieId bookie id * @param version version of the cookie data * @throws BookieException when fail to remove cookie */ void removeCookie(String bookieId, Version version) throws BookieException; /** * Prepare ledgers root node, availableNode, readonly node.. * * @return Returns true if old data exists, false if not. */ boolean prepareFormat() throws Exception; /** * Initializes new cluster by creating required znodes for the cluster. If * ledgersrootpath is already existing then it will error out. * * @return returns true if new cluster is successfully created or false if it failed to initialize. * @throws Exception */ boolean initNewCluster() throws Exception; /** * Do format boolean. * * @return Returns true if success do format, false if not. */ boolean format() throws Exception; /** * Nukes existing cluster metadata. * * @return returns true if cluster metadata is successfully nuked * or false if it failed to nuke the cluster metadata. * @throws Exception */ boolean nukeExistingCluster() throws Exception; } 2 notes:
- i posted also my test class code to be sure there is no conflict in using a parameterized test and mockito
- from what i was able to understand the problem is byteBuddy more than mockito itself but i don't know how to fix this.
Mockito version i'm using is 3.0.0 Bytebuddy version is 1.9.3
I hope you can help me, have a good day all :P