简体   繁体   中英

Mock a New Object instance in a Abstract Class

I have a AbstractDao class, where I am instantiating Rest Fore API. I am not able to mock the new forceAPI(config) in Power Mock. Please suggest.

public abstract class AbstractDao {

@Inject
private Configuration configuration;

public ForceApi getForceAPI() {
    ApiConfig config = new ApiConfig();
    config.setClientId("test");
    config.setClientSecret("test");
    config.setUsername("test");
    config.setPassword("test");
    config.setLoginEndpoint("test");
    return new ForceApi(config);
}

}

I am trying to do in this way but it's not working. My DAO class is extending Abstract DAO class

@RunWith(BlockJUnit4ClassRunner.class)
public class SalesForceDaoImplTest {

@InjectMocks
private SalesForceDaoImpl salesForceDao;
@Mock
private ForceApi forceApiMock;
@Mock
private ApiConfig apiConfigMock;
@Mock
private Configuration configMock;
@Mock
JsonObject jsonobject;


@Before
public void setup() {
    initMocks(this);
    when(configMock.getAppConfiguration()).thenReturn(jsonobject);
    when(jsonobject.getString(anyString())).thenReturn("test");
    when(salesForceDao.getForceAPI()).thenReturn(forceApiMock);
    when(new ApiConfig()).thenReturn(apiConfigMock);
    when(new ForceApi(apiConfigMock)).thenReturn(forceApiMock);
}

Probably this is a late reply, but I believe it still can be useful to some of us, programmers.

Disclaimer: I've never worked with PowerMockito but I've used PowerMock quite a lot As for troig's suggestion: PowerMock driven unit test assumes that you'll run with a dedicated runner:

@RunWith(PowerMockRunner.class)

In this case this clashes with @RunWith(BlockJUnit4ClassRunner.class) stated in the question, so the "slot" for RunWith is already occupied.

This particular one can still be resolved by running recent versions of power mock as a JUnit's rule (I assume you run JUnit) You can find an example of doing this here But bottom line this is one of known issues with power mock.

There are other issues as well which basically made me to come to conclusion that the power mock should be avoided and should not be used in new project (and Power Mockito as well):

  • The unit test with power mock is slow (much slower than, say with EasyMock if it could be rewritten for using that)

  • The Power Mock sometimes instruments the byte code incompatible with tools like jacoco code coverage and as a consequence sonar doesn't cover classes unit tested with power mock or at least does it wrong

  • Surefire plugin responsible for running tests in maven has a feature of running multiple unit tests in parallel. Sometimes with power mock its not possible.

  • Even IntelliJ sometimes fails to run suits that contain power mock tests.

But the most important thing is that when you have to use tools like power mock, probably the code can (and should) be refactored to be more clean and easy-to-understand. Regarding your particular question:

Your class violates the coding principle that says that the class should not take care of dependencies of itself. Here DAO actually "constructs" and configures another (external) service for a later use.

I suggest you to watch an excellent lecture of Misko Hevery about clean code to better understand what I mean

So again, in your example. Its much better to maintain the ForceApi as a dependency constructed by Dependency Injection framework (I see that you already use @Inject so you're on the right track)

Take a look at this implementation:

public abstract class AbstractDao {

  @Inject // this one is constructed and injected by your favorite DI framework in real use cases
  private ForceApi forceApi;

  public void doSomething() {
       // do your dao stuff here
       forceApi.callSomeAPIMethod();
       // do your dao stuff here
  }    
}

Now for unit tests you don't really need power mock anymore. Its enough to use a simple Mock or even Stub depending on situation. All you need is to provide a constructor that will take a parameter of type ForceApi or maybe a setter (you can consider make it package private so that noone would be able to call it outside the test).

I don't have enough information out of your question, but the design I've offered probably can eliminate the need to have an Abstract class for the DAO, which is also can be helpful in some cases because inheritance sometimes can be a pretty heavy 'obligation' to maintain (at least think about this). And maybe in this case the inheritance is done only to support this getForceAPI behavior. In this case as the project grows, probably some methods will be added into this AbstractDAO just because its convenient to do so, but these methods will 'transparently' be added at this point to the whole hierarchy to all DAOs. This construction becomes fragile, because if at least one method changes its implementation the whole hierarchy of DAOs can potentially fail.

Hope this helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM