#Component
public class SomeFactory implements ISomeFactory {
public someWatchFactory() {};
#Override
public boolean startWatch(MethodToWatch methodName, UUID uniqueID, Callable toRun) {
IPerformanceStopWatch mywatch = getStartWatch(methodName,uniqueID,toRun);
return mywatch.startWatchDeployTaskStatus();
}
#Lookup
private IPerformanceStopWatch getStartWatch(MethodToWatch methodName, String uniqueID, Callable toRun) {
IPerformanceStopWatch mywatch = getStartWatch(methodName,uniqueID,toRun);
return null; //stub implementation which will be replaced by the container
}
}
I would like to test the factory class, using something like:
#InjectMock
ISomeFactory someFactory;
#Mock
IPerformanceStopWatch performanceWatch
That whenever the lookup annotation inside the SomeFactory class will try to get the instance, it will use the mock.
How should i do it?
Related
I am trying to write unit tests for a class having spring retry using the springRunner. But my #Autowired beans are null . Could you please let me know what I did wrong?
Below is my test class
#RunWith(SpringRunner.class)
#ContextConfiguration
public class DeltaHelperTest {
#Autowired
private DeltaHelper deltaHelper;
#Before
public void setUp() { System.setProperty("delta.process.retries", "2"); }
#After
public void validate() { validateMockitoUsage(); }
#Test
public void retriesAfterOneFailAndThenPass() throws Exception {
when(deltaHelper.restService.call(any(), any())).thenThrow(new HttpException());
deltaHelper.process(any(),any());
verify(deltaHelper, times(2)).process(any(), any());
}
#Configuration
#EnableRetry
#EnableAspectJAutoProxy(proxyTargetClass=true)
#Import(MockitoSkipAutowireConfiguration.class)
public static class Application {
#Bean
public DeltaHelper deltaHelper() {
DeltaHelper deltaHelper = new DeltaHelper();
deltaHelper.myStorageService= myStorageService();
deltaHelper.restService = restService();
return deltaHelper;
}
#Bean
public MyStorageService myStorageService() {
return new MyStorageService();
}
#Bean
public MyRestService restService() {
return new MyRestService();
}
#Bean
public MyRepo myRepository() {
return mock(MyRepo.class);
}
}
#Configuration
public static class MockitoSkipAutowireConfiguration {
#Bean MockBeanFactory mockBeanFactory() {
return new MockBeanFactory();
}
private static class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
#Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return !mockingDetails(bean).isMock();
}
}
}
}
Here test service is null on deltaHelper object .
MyRepo.class is mocked as it has some more #autowired bean reference
Attaching other classes here
#Component
public class DeltaHelper {
#Autowired
MyRestService restService;
#Autowired
MyStorageService myStorageService;
#NotNull
#Retryable(
value = Exception.class,
maxAttemptsExpression = "${delta.process.retries}"
)
public String process(String api, HttpEntity<?> entity) {
return restService.call(api, entity);
}
#Recover
public String recover(Exception e, String api, HttpEntity<?> entity) {
myStorageService.save(api);
return "recover";
}
}
#Service
public class MyStorageService {
#Autowired
MyRepo myRepo;
#Async
public MyEntity save(String api) {
return myRepo.save(new MyEntity(api, System.currentTimeMillis()));
}
}
public class MyRestService extends org.springframework.web.client.RestTemplate {
}
Thank you
Tried MockitoJUnitRunner, But found that #Retryable works only when running with Spring
I'm not sure why you are trying to test framework functionality such as retry. Generally, you can assume that framework components have been tested thoroughly by the framework authors.
Ignoring that, I can see at least two problems:
deltaHelper is not a mock, but your SUT, yet you try to set up method calls. If you mock your SUT, you are no longer testing your class, you are testing the mock. If you want your call to fail, don't mock the call, but mock its dependencies (e.g. MyRestService restService) and have calls on the dependency throw an exception.
You pass ArgumentMatchers.any() in your real method call (the "act" part), but any() unconditionally returns null (not some magic object). If you want to act on your SUT, you must pass real values. any is for setting up mocks or verifying calls on mocks.
For completeness' sake, here's the source of any():
public static <T> T any() {
reportMatcher(Any.ANY);
return null;
}
Assuming that I have this repository
#Repository public class GenericHistoryRepositoryImpl implements GenericHistoryRepository {
#Autowired private MongoTemplate mongoTemplate;
#Override public Historiable create(Historiable historiableObject, String collectionName) {
mongoTemplate.save(historiableObject, collectionName);
return historiableObject; }
#Override public <T extends Historiable> T get(String id, Class<T> collectionClass, String collectionName) {
Query query = new Query();
query.addCriteria(Criteria.where("id").is(id));
return mongoTemplate.findOne(query, collectionClass, collectionName);
} }
And I have this test in which I have to mock the repository, but I can't figure out how
#RunWith(MockitoJUnitRunner.class)
public class GenericHistoryServiceTest {
#Mock
private GenericHistoryRepository genericHistoryRepository;
#InjectMocks
private GenericHistoryService genericHistoryService = new GenericHistoryServiceImpl();
#Test
public <T extends Historiable> void getHistoryOk2() throws NotFoundException, ClassNotFoundException {
String id = "1"
;
String collectionName = HistoriableCollections.HISTORIABLE_SHIPMENT_REQUEST;
ShipmentRequest a = mock(ShipmentRequest.class);
Class<? extends Historiable> clazz = ShipmentRequest.class;
when(genericHistoryRepository.get(any(String.class), eq(clazz), collectionName)).thenReturn(createExample());
HistoriableDTO result = genericHistoryService.get(id, HistoriableCollections.HISTORIABLE_SHIPMENT_REQUEST);
// verify(genericHistoryRepository, times(1)).get(id, any(), HistoriableCollections.HISTORIABLE_SHIPMENT_REQUEST);
assertThat(result, is(notNullValue()));
assertThat(result.getId(), is(notNullValue()));
}
Keep in mind that Historiable is an abstract class
public abstract class Historiable {
public abstract String getParentId();
}
And this extends Historiable
#Document(collection = HistoriableCollections.HISTORIABLE_SHIPMENT_REQUEST)
public class ShipmentRequest extends Historiable {
private String id;
#Indexed
private String parentId;
...
}
My problem is with the "when" sentence defining the behaviour of the repository mock. It has generic methods that I don't know how to mock
Class<? extends Historiable> clazz = ShipmentRequest.class;
when(genericHistoryRepository.get(any(String.class), eq(clazz), collectionName)).thenReturn(createExample());
I'm getting
The method thenReturn(capture#1-of ? extends Historiable) in the type OngoingStubbing<capture#1-of ? extends Historiable> is not applicable for the arguments (ShipmentRequest)
private ShipmentRequest createExample() {
ShipmentRequest history = new ShipmentRequest();
history.setId("1");
return history;
}
Your when clause is the problem.
Inside the when you should define when to match and after that you state what should be returned.
Your when statement starts good by stating you want to match any String passed as first argument, but as a second argument you are passing a mock so that means that it will only trigger if that specific mock is passed as second argument (which I don't think is happening).
You can change the second argument to: any(Class.class)
For the third argument you can state that you want it to be equal to collectionName by using: org.mockito.ArgumentMatchers#eq(T)
In your test class you can have something like this
public class TestClass {
#Mock
GenericHistoryRepository genericHistoryRepository;
#InjectMock
MongoTemplate mongoTemplate;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
}
#InjectMock will inject the depedency of your mock.
How to mock super class method using power mock. In CardRepo in am using superclass method to get jdbcTemplate but using power mock i am not able to mock super.method in CardRepo class. how to mock super.getJdbcTemplate() using power mock.
public abstract class AbstractRepository {
#Autowire
private static JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
}
Class CardRepo extends AbstractRepository{
#Override
public List<Card> getCardList(CommonInputBean inputBean) {
List<Card> data=Collections.emptyList();
data = super.getJdbcTemplate().query(query.toString(), new BeanRowMapper<Card>(Card.class)); // how to mock
return data;
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({ CardRepo.class})
class CardTest{
#Spy
private CardRepo cardRepository = new CardRepo();
#Test
public void getCardList() {
Method method = PowerMockito.method(AbstractRepository.class, "getJdbcTemplate");
PowerMockito.suppress(method);
Method methodFoo = PowerMockito.method(AbstractRepository.class, "getJdbcTemplate");
PowerMockito.replace(methodFoo).with(new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return jdbcTemplate;
}
});
PowerMockito.suppress(MemberMatcher.methodsDeclaredIn(AbstractRepository.class));
CardRepositoryImpl child = PowerMockito.spy(new CardRepositoryImpl());
child.getJdbcTemplate();
PowerMockito.when(child.getJdbcTemplate()).thenReturn(jdbcTemplate);
List<Card> list = this.cardRepository.getCardList(inputBean);
}
}
Example of the problem:
class ToBeTested {
private MyResource myResource;
public toBeTested() {
this.myResource = getResource();
}
private MyResource getResource() {
//Creating My Resource using information form a DB
return new MyResource(...);
}
}
I would like to mock the getResource() so I would be able to provide a mock instance of MyResource. All the examples I found on how to mock a private method are based on first creating the ToBeTested instance and then replace the function but since it's being called from the constructor in my case it's to late.
Is it possible to mock the private function to all instances in advance of creating them?
Not directly but, you can suppress and then simulate with power mockito
#RunWith(PowerMockRunner.class)
#PrepareForTest(ToBeTested .class)
public class TestToBeTested{
#before
public void setup(){
suppress(method(ToBeTested.class, "getResource"));
}
#Test
public void testMethod(){
doAnswer(new Answer<Void>() {
#Override
public MyResource answer(InvocationOnMock invocation) throws Throwable {
return new MyResource();
}
}).when(ToBeTested.class, "getResource");
}
ToBeTested mock = mock(ToBeTested.class);
mock.myMethod();
//assert
}
I have the DataPrepareService that prepare data for reports and I have an Enum with report types, and I need to inject ReportService into Enum or have access to ReportService from enum.
my service:
#Service
public class DataPrepareService {
// my service
}
my enum:
public enum ReportType {
REPORT_1("name", "filename"),
REPORT_2("name", "filename"),
REPORT_3("name", "filename")
public abstract Map<String, Object> getSpecificParams();
public Map<String, Object> getCommonParams(){
// some code that requires service
}
}
I tried to use
#Autowired
DataPrepareService dataPrepareService;
, but it didn't work
How can I inject my service into enum?
public enum ReportType {
REPORT_1("name", "filename"),
REPORT_2("name", "filename");
#Component
public static class ReportTypeServiceInjector {
#Autowired
private DataPrepareService dataPrepareService;
#PostConstruct
public void postConstruct() {
for (ReportType rt : EnumSet.allOf(ReportType.class))
rt.setDataPrepareService(dataPrepareService);
}
}
[...]
}
weekens' answer works if you change inner class to static so spring can see it
Maybe something like this:
public enum ReportType {
#Component
public class ReportTypeServiceInjector {
#Autowired
private DataPrepareService dataPrepareService;
#PostConstruct
public void postConstruct() {
for (ReportType rt : EnumSet.allOf(ReportType.class))
rt.setDataPrepareService(dataPrepareService);
}
}
REPORT_1("name", "filename"),
REPORT_2("name", "filename"),
...
}
There is one another approach you may like to explore. However instead of injecting a bean into enum it associates a bean with an enum
Say you have an enum WidgetType and Widget class
public enum WidgetType {
FOO, BAR;
}
public class Widget {
WidgetType widgetType;
String message;
public Widget(WidgetType widgetType, String message) {
this.widgetType = widgetType;
this.message = message;
}
}
And you want to create Widgets of this type using a Factory BarFactory or FooFactory
public interface AbstractWidgetFactory {
Widget createWidget();
WidgetType factoryFor();
}
#Component
public class BarFactory implements AbstractWidgetFactory {
#Override
public Widget createWidget() {
return new Widget(BAR, "A Foo Widget");
}
#Override
public WidgetType factoryFor() {
return BAR;
}
}
#Component
public class FooFactory implements AbstractWidgetFactory {
#Override
public Widget createWidget() {
return new Widget(FOO, "A Foo Widget");
}
#Override
public WidgetType factoryFor() {
return FOO;
}
}
The WidgetService is where most of the work happens. Here I have a simple AutoWired field which keeps tracks of all the registered WidgetFactories. As a postConstruct operation we create a map of the enum and the associated factory.
Now clients could inject the WidgetService class and get the factory for the given enum type
#Service
public class WidgetService {
#Autowired
List<AbstractWidgetFactory> widgetFactories;
Map<WidgetType, AbstractWidgetFactory> factoryMap = new HashMap<>();
#PostConstruct
public void init() {
widgetFactories.forEach(w -> {
factoryMap.put(w.factoryFor(), w);
});
}
public Widget getWidgetOfType(WidgetType widgetType) {
return factoryMap.get(widgetType).createWidget();
}
}
Enums are static, so you have to figure out a way to access to the beans from a static context.
You can create a class named ApplicationContextProvider that implements the ApplicationContextAware interface.
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextProvider implements ApplicationContextAware{
private static ApplicationContext appContext = null;
public static ApplicationContext getApplicationContext() {
return appContext;
}
public void setApplicationContext(ApplicationContext appContext) throws BeansException {
this.appContext = appContext;
}
}
then add this your application context file:
<bean id="applicationContextProvider" class="xxx.xxx.ApplicationContextProvider"></bean>
after that you could access to the application context in a static way like this:
ApplicationContext appContext = ApplicationContextProvider.getApplicationContext();
it will be hard to control that the spring container is already up and running at the time the enum is instantiated (if you had a variable with this type in a test-case, your container will usually not be there, even aspectj autowiring won't help there). i would recommend to just let the dataprepare-service or something give you the specific-params with a lookup-method with the enum-parameter.
I think this what you need
public enum MyEnum {
ONE,TWO,THREE;
}
Autowire the enum as per usual
#Configurable
public class MySpringConfiguredClass {
#Autowired
#Qualifier("mine")
private MyEnum myEnum;
}
Here is the trick, use the factory-method="valueOf" and also make sure
lazy-init="false"
so the container creates the bean upfront
<bean id="mine" class="foo.bar.MyEnum" factory-method="valueOf" lazy-init="false">
<constructor-arg value="ONE" />
</bean>
and you are done!
Just pass it to the method manually
public enum ReportType {
REPORT_1("name", "filename"),
REPORT_2("name", "filename"),
REPORT_3("name", "filename")
public abstract Map<String, Object> getSpecificParams();
public Map<String, Object> getCommonParams(DataPrepareService dataPrepareService){
// some code that requires service
}
}
As long as you call the method only from managed beans, you can inject it in these beans and pass the reference to the enum on each call.
Maybe you can use this solution ;
public enum ChartTypes {
AREA_CHART("Area Chart", XYAreaChart.class),
BAR_CHART("Bar Chart", XYBarChart.class),
private String name;
private String serviceName;
ChartTypes(String name, Class clazz) {
this.name = name;
this.serviceName = clazz.getSimpleName();
}
public String getServiceName() {
return serviceName;
}
#Override
public String toString() {
return name;
}
}
And in another class which you need the bean of the Enum :
ChartTypes plotType = ChartTypes.AreaChart
Object areaChartService = applicationContext.getBean(chartType.getServiceName());