I'm trying to figure out why Mockit is not working for the following code:
public class TestClass {
#Test
public void test() {
Mockit.redefineMethods(ExecuterClass.class, new Object() {
#SuppressWarnings("unused")
public SomeService getService() {
return new MockSomeServiceImpl();
}
});
// Code to run test
}
}
public abstract class ExecuterClass<T,U,V,W> {
// Other methods/variables
public SomeService getService() {
return someProvider.getService();
}
}
public interface SomeService {
// Some method definitions
}
public class MockSomeServiceImpl implements SomeService {
// Some method implementations
}
The error I get back is:
java.lang.IllegalAccessError: tried to access class TestClass from class ExecuterClass
Any ideas on how to fix this?? In the end, I would like the test to use the MockSomeServiceImpl methods rather than those in SomeService implementation.
SomeService was generated by a WSDL, so I don't have the implementation that someObject.getService() returns. So I can't do Mockit.redefineMethods(SomeServiceImpl.class, MockSomeServiceImpl.class)
Related
I use junit5+mockito to do some test, and I can mock/inject normal class/method, but I cannot mock/inject class called by application context, pls refer to the following code:
Target
public class util implements ApplicationContextAware {
private static ApplicationContext applicationContextSingleton;
public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
return applicationContextSingleton.getBeansOfType(clazz);
}
// ....
}
public interface IA {
List<String> methodInA(balabala...);
}
class A implements IA{
private somethingA;
#Override
public List<String> methodInA(params...){
// some code ...
}
}
class B {
private somethingB;
public methodInB(){
// some code ...
util.getBeansOfType(IA.class).get("A").methodInA(balabala...)
// some code ...
}
}
Test
#SpringBootTest
class BTest{
#Test
void methodInBTest(){
// how to mock/spy/stub/inject class A (or methodInA from class A, or somethingA in class A)
}
}
Attempt
I used following code, and found the class A was inject by mockito, but no real instance was created, so I cannot use when() or verify() to the member or method in class A
#SpringBootTest
#SpyBean(A.class)
class BTest{
#Test
void methodInBTest(){
// how to mock/spy/stub/inject class A (or methodInA in class A, or somethingA in class A)
}
}
Question
how to mock/spy/stub/inject class A (or methodInA, or somethingA in class A) ?
I have two projects in eclipse siteBase and siteCustom
siteBase have controller
public final class BaseController{
#Autowired
BaseService service;
#POST
#Path(/test)
public final boolean test() {
try {
service.test();
}
catch (Throwable ex) {
processException(ex);
}
return true;
}
}
A BaseService Interface
public interface BaseService extends BasicService{
boolean test();
}
And a BaseService Implementation
public class BaseServiceImpl implements BaseService {
public boolean test() {
System.out.println("BaseServiceImpl");
return true;
}
}
And in the siteCustom I have a other Implementation
public class BaseServiceCustomImpl implements BaseService {
public boolean test() {
System.out.println("BaseServiceCustomImpl");
return true;
}
}
As I expect, when I run siteBase and call test controller have a console print:
BaseServiceImpl
And if I run siteCustom and call test controller have a console print:
BaseServiceCustomImpl
(I hope the code it's ok, but it's not problem, it's only for example purpose and It's not tested, it's only to explain the situation)
The other day, suddenly, when I run siteCustom the console show BaseServiceImpl... after some update it again works ok the console shows BaseServiceCustomImpl, but I want to understand exactly how Spring uses the Implementation and when and where decide which Implementation and its methods use.
I have this method to get my services
public <T extends ServiceInterface> T getService(Class<T> aServiceClass);
I would like to instantiate the class "MyService" that extends to ServiceInterface with this method.
How to do that? should I make a new MyService object to pass it as a parameter? but if I do that the get service method will not be useful.
If I understand your question, you want to create a class MyService, that extends ServiceInterface. And you want to get your Service by the method getService(Class<T> aServiceClass>), right? That would look like this (but please split the classes in different files):
package test;
public class Test2 {
public static void main(String[] args) {
MyService m = getService(MyService.class);
//m.someMethod(...);
}
public static <T extends ServiceInterface> T getService(Class<T> aServiceClass) {
return null; //??
}
//class MyService
public class MyService extends ServiceInterface{
//someMethods...
}
//class ServiceInterface
public class ServiceInterface {
public <T extends ServiceInterface> T getService(Class<T> aServiceClass) {
return null; //whatever the method is doing
}
}
}
How to test a class which depends on Provider<>?
Please see the code below.
class ToTest {
#Inject
Provider<Processor> processorProvider;
public buildData() {
processorProvider.get().process();
}
class ProcessorProviderImpl implements Provider<Processor> {
#Inject
private Handler someHandler;
public Processor get() {
return new MyProcessor(somehandler)
}
}
public static class TestModule extends JukitoModule {
#Override
protected void configureTest() {
bind(Processor.class).toProvider(
ProcessorInstanceProviderImpl.class);
bindMock(SubHandler.class).in(TestSingleton.class);
}
}
class Handler {
#Inject
private SubHandler subHandler; // this is singleton instance
}
}
So when I mock subHandler it doesn't work and when I run unit test I am getting a NullPointerException where subHandler.handle() is getting called.
You can use Providers.of() to initialize processorProvider with a provider of your collaborator instance.
https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/util/Providers.html
test = new ToTest();
test.processorProvider = Providers.of(processorMock);
I have the following class:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = AppleFactory.createInstance(someStringVariable);
....
....
....
}
}
And the Test class:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#InjectMocks
MyClass myClass;
#Test
public void myMethod(){
...
...
...
}
}
How could I inject an Apple instance as a mock in MyClass?
You have 3 possibilities to solve this:
Abstract factory: Instead of using a static method, use a concrete factory class:
public abstract class AppleFactory {
public Apple createInstance(final String str);
}
public class AppleFactoryImpl implements AppleFactory {
public Apple createInstance(final String str) { // Implementation }
}
In your test class, mock the factory:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private AppleFactory appleFactoryMock;
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Before
public void setup() {
when(appleFactoryMock.createInstance(Matchers.anyString()).thenReturn(appleMock);
}
#Test
public void myMethod(){
...
...
...
}
}
PowerMock: Use PowerMock to create a mock of a static method. Look at my answer to a relevant question to see how it's done.
Testable class: Make the Apple creation wrapped in a protected method and create a test class that overrides it:
public class MyClass {
private Apple apple;
public void myMethod() {
apple = createApple();
....
....
....
}
protected Apple createApple() {
return AppleFactory.createInstance(someStringVariable);
}
}
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Test
public void myMethod(){
...
...
...
}
private class TestableMyClass extends MyClass {
#Override
public void createApple() {
return appleMock;
}
}
}
Of course, in your test class you should test TestableMyClass and not MyClass.
I'll tell you my opinion on each of the methods:
The abstract factory method is the best one - This is a clear design that hides the implementation details
The testable class - Is the second option which requires minimum changes
The PowerMock option is my least favorite - Instead of going for a better design, you ignore and hide your problem. But that's still a valid option.
In addition of the solution proposed by Avi, you can choose a fourth possibility:
Inject into Factory:
This is, for me, the best option when you already have code to refacrot. With this solution you don't have to change porduction code but only factory class and test.
public class AppleFactory
{
private static Apple _injectedApple;
public static createInstance(String str)
{
if (_injectedApple != null)
{
var currentApple = _injectedApple;
_injectedApple = null;
return currentApple;
}
//standard implementation
}
public static setInjectedApple(Apple apple)
{
_injectedApple = apple;
}
}
Now you can use your static factory simply:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Mock
private Apple appleMock;
#InjectMocks
MyClass myClass;
#Before
public void setup() {
AppleFactory.setInjectedApple(appleMock);
}
#Test
public void myMethod(){
...
...
...
}
}