Mockito object methods of another class - java

Hi I request your help to know how to emulate the method of the class Validator.validateConnection();.
The problem is that the method validateConnection not exist in the class Class_Implementation and I don't want to create that method in the class Class_Implementation. The method validateConnection do a connection to the database to know if the connection is alive. When Mockito runs I get a java.Lang.NullPointerException that is caused by NamingException - need to specify class name in environment.
The real problem is when I call in Mockito test the line:
Boolean resp = mockImpl.checkConnection();
..in the checkConnection() the class Validator.validateConnection(); is trying to connect to database. I just want emulate this line and return true or false, but the problem is that the method validateConnection() is an instance of class Validator.
If need more information for fix this please let me know.
public class Class_Implementation {
public boolean checkConnection() {
boolean isConnectionAlive = false;
Validator.validateConnection();
// another things for do
return false;
}
}
public class Validator {
public static Boolean validateConnection() {
Connection conn = new Connection();
Boolean connectionAlive = false;
connectionAlive = conn.isConnectionAlive();
if (connectionAlive) {
return true;
} else {
return false;
}
}
}
public class Connection {
public boolean isConnectionAlive() {
// Code for connection to DB
}
}
// class for do the test
#RunWith(PowerMockRunner.class)
#PrepareForTest({Class_Implementation.class,Validator.class})
public class TestConnection {
#Test
public void validate_Connection() throws Exception {
Class_Implementation mockImpl = PowerMock.createPartialMock(Class_Implementation.class);
PowerMock.mockStatic(Validator.class);
PowerMockito.when(mockImpl, Validator.validateConnection() ).thenReturn(true);
PowerMock.replayAll(mockImpl);
Boolean resp = mockImpl.checkConnection();
PowerMock.verifyAll();
Validate.notNull(resp);
}
}

Use a Validator object instead of its static methods and inject the Validator into Class_Implementation (by constructor). This is called Dependency Injection. In your test you can inject a mock of the Validator.
public class Validator {
public boolean validateConnection() {
...
}
}
public class Class_Implementation {
private final Validator validator;
public Class_Implementation(Validator validator) {
this.validator = validator;
}
public boolean checkConnection() {
...
validator.validateConnection();
...
}
}
public public class Class_ImplementationTest {
#Test
public void validate_Connection() throws Exception {
Validator validator = Mockito.mock(Validator.class);
Mockito.when(validator.validateConnection()).thenReturn(true);
Class_Implementation impl = new Class_Implementation(validator);
boolean response = mockImpl.checkConnection();
Assert.assertTrue(response);
}
}
I made some additional changes to your code.
Don't return a Boolean object if there are only two states.
A Unit test tests on class and is named like the class with an additional Test prefix.
You don't need PowerMock if you have nice code.

Just mock your Class_Implementation (you should change the name and stick to Java naming standards by the way) and stub the validateConnection() method:
final Class_Implementation mock = mock(Class_Implementation.class);
when(mock.checkConnection()).thenReturn(true); // or false
But anyway, what you should mock is the interface to start with.

Related

PowerMock/JUnit/Guice - Mocking the Private Construction with Injection

I have a class which is using the GUICE DI and I am trying to write a unit test for this. Here i have two issue, one is the private constructor and 2nd is its injected with parameters. Any help how to write a test case for this. Here is the sample code.
public class DataServiceMngr {
Utility objUtility;
Service ObjService;
#Inject
private DataServiceMngr(Utility objUtility, Service ObjService) {
this.objUtility = objUtility;
this.ObjService = ObjService;
}
public String fetchData() {
return "DATA_FETCHED";
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest({Utility.class, DataServiceMngr.class})
public class UtilityTest {
#Test
public void TestStaticMethod_WithPowerMockito() {
String callexpectation = "DATA_FETCHED";
DataServiceMngr mgr = PowerMockito.mock(DataServiceMngr.class);
assertEquals(callexpectation, mgr.fetchData());
}
}

Why doesn't my #Transactional method rollback when testing?

I have #transactional method that seems to be working (rolling back) if run the actual service and provide inputs that would cause a run-time error. If I create a Test for that method that throws a run-time error it doesn't seem to rollback anymore. Any idea why this doesn't work while testing?
it's somthing like:
#Service
public class SampleServiceImpl implements SampleService {
private final RepoA repoA;
private final RepoB repoB;
public SampleServiceImpl(RepoA repoA, RepoB repoB) {
this.repoA = repoA,
this.repoB = repoB
}
#Transactional
#Override
public void addItems() {
repoA.save(new ItemA(1,'name1')); //works
repoB.save(new ItemB(2,'name2')); //throws run-time error
}
}
#RunWith(SpringRunner.class)
#DataJpaTest
public class Tests {
#Autowired
private RepoA repoA;
#Mock
private Repob repoBMock;
#Test
public void whenExceptionOccurrs_thenRollsBack() {
var service = new SampleService(repoA, repoBMock);
Mockito.when(repoBMock.save(any(ItemB.class))).thenThrow(new RuntimeException());
boolean exceptionThrown = false;
try {
service.addItems()
} catch (Exception e) {
exceptionThrown = true;
}
Assert.assertTrue(exceptionThrown);
Assert.assertFalse(repoA.existsByName('name1')); // this assertion fails because the the first item still exists in db
}
}
Just add annotation Rollback and set the flag to false.
#Test
#Rollback(false)

Method of mocked object returns null after interface downcast

I am trying to write tests for Spring boot application.
There are two interfaces INotifier, and IMonospaceNotifier which extends INotifier in the application.
public interface INotifier {
void send(String message);
}
public interface IMonospaceNotifier extends INotifier {
String monospace(String message);
}
Class TelegramNotifier implements IMonospaceNotifier
#Component
public class TelegramNotifier implements IMonospaceNotifier {
//Some code omitted
public void send(String message) {
//Implementation omitted
}
#Override
public String monospace(String message) {
return "```\n" + message + "\n```";
}
}
Class Report has field of type INotifier but in some cases, it is downcasted to IMonospaceNotifier
#Component
public class Report {
//Some code is omitted
private INotifier notifier;
#Autowired
public Report(/*params are omitted*/) {
// Some code is omitted
if (reportGenerator.requireMonospace() && !(notifier instanceof IMonospaceNotifier)) {
throw new IllegalArgumentException("If reportGenerator requests monospace method" +
" then notifier should be IMonospaceNotifier");
}
}
#Scheduled(cron = "${reportSchedule}")
public void sendReport() {
// Some code is omitted
String report = reportGenerator.generate(workerList);
if (reportGenerator.requireMonospace()) {
if (notifier instanceof IMonospaceNotifier) {
/**
* This is the problem part. It works fine with normal obejcts
* but method `monospace` returns null with mocked objects.
* I debugged it this codeline is definitely executed and
* `report` is not `null` before the execution of this line
*/
report = ((IMonospaceNotifier) notifier).monospace(report);
} else {
assert true : "Should never happen, checked in constructor";
}
}
notifier.send(report);
}
It all works fine until IMonospaceNotifier is mocked. With mocked version
IMonospaceNotifier.monospace() returns null (Please see comment in the code above). Mocked object seems to have the correct type IMonospaceNotifier$$EnhancerByMockitoWithCGLIB$$...
The object is mocked in the next way:
#RunWith(SpringRunner.class)
#SpringBootTest(properties = "scheduling.enabled=false")
public class MonitorTest {
#MockBean
private IMonospaceNotifier notifier;
#Test
public void doNothing(){
/** `notifier.send` is invoked in another bean constructor.
* That's why it is working without actual invocation. */
// This works fine as it doesn't use Report class and downcast
verify(notifier).send("Hi!, I'm starting");
// The next invocation is actually null
verify(notifier).send(matches("```┌───.*Worker Name.*"));
verify(notifier).send("I'm shutting down. Good Bye!");
}
}
This is how INotifier is invoked in a constructor of Monitor bean
#Service
public class Monitor {
#Autowired
public Monitor(/*params are omitted*/ INotifier notifier) {
// This line works fine as it doesn't invoke `monospace`
notifier.send("Hi!, I'm starting");
// In `Report` `send()` is executed with `null` as parameter
// because `monospace()` was invoked
report.sendReport();
}
}
You have to tell your mock to return what you want. In your case it looks like you want to return the same object passed in as parameter:
public class MonitorTest {
#MockBean
private IMonospaceNotifier notifier;
#Test
public void doNothing(){
doAnswer((invocation)-> invocation.getArguments()[0]).when(notifier).monospace(anyString());
// ...
The better option however is to define an independent "report" to be returned so that you have more control in the test case:
public class MonitorTest {
#MockBean
private IMonospaceNotifier notifier;
#Test
public void doNothing(){
doReturn(SOME_TEST_REPORT_STRING).when(notifier).monospace(anyString());
// ...

Google Guice: Mock a #provides method consists of set of object

I have class A which is taking a set as guice dependency. The set is singleton. Below is the code example:
class A
{
private Set<InetAddress> set;
private String pingUriPath;
#Inject
public A(Set<InetAddress> set, #Named("pingUri") String pingUriPath)
{
this.set = set;
this.pingUriPath = pingUriPath; // this is used somewhere
}
public void storeValue(String str)
{
if(str.equals("abc"))
{
set.add(str);
}
}
}
Here is the guice module that injects dependency:
private class GuiceModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return Sets.newConcurrentHashSet();
}
}
I want to mock the method storeValue and for that i have to mock the set. I am not able to mock the set using guice.
If i mock like below, it gives assertion error(no interactions with this mock)
#Mock
Set<InetAddress> mockHealthyTargets;
private class MockClassesModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return Sets.newConcurrentHashSet();
}
}
public test_storeValue()
{
Injector injector = Guice.createInjector(new MockClassesModule());
A a = injector.getInstance(A.class);
a.storeValue("abc");
verify(mockHealthyTargets).add("abc")
}
If you have the need to use guice in your unit tests, something is most likely going the wrong direction. One of the biggest benefits of dependency injection is that testing becomes easy, because you can pass dependencies that are controlled by you.
I assume you want to test the class A and specifically the method storeValue. For this you don't even need mocking
#Test
public void test() {
// prepare dependencies
Set<InetAddress> set = Sets.newConcurrentHashSet();
String pingUri = "example.com";
// prepare input
String input = "someValue";
// prepare class under test
A classUnderTest = new A(set, pingUri);
// call class under test
classUnderTest.storeValue(input);
// check that what you expected happened
// in this case you expect that the dependency set now contains the input
assertThat(set, contains(input));
}
I have found what the mistake was, I should return mock when providing to my unit test. It should look like this:
#Mock
Set<InetAddress> mockHealthyTargets;
private class MockClassesModule extends AbstractModule {
#Override
public void configure() {
bindConstant().annotatedWith(Names.named("pingUri")).to("/ping");
}
#Provides
#Singleton
Set<InetAddress> healthyTargets(){
return mockHealthyTargets;
}
}

Spring AOP CGLIB proxy's field is null

Description
Using the vlcj component, the custom component appears as a result of the AOP proxy object null.
MediaList Class
public class MediaList {
private libvlc_media_list_t mediaListInstance;
public MediaList(LibVlc libvlc, libvlc_instance_t instance, libvlc_media_list_t mediaListInstance) {
this.libvlc = libvlc;
this.instance = instance;
createInstance(mediaListInstance);
}
private void createInstance(libvlc_media_list_t mediaListInstance) {
logger.debug("createInstance()");
if(mediaListInstance == null) {
mediaListInstance = libvlc.libvlc_media_list_new(instance);
}
else {
libvlc.libvlc_media_list_retain(mediaListInstance);
}
this.mediaListInstance = mediaListInstance; // <- assignment
logger.debug("mediaListInstance={}", mediaListInstance);
mediaListEventManager = libvlc.libvlc_media_list_event_manager(mediaListInstance);
logger.debug("mediaListEventManager={}", mediaListEventManager);
registerEventListener();
}
public final libvlc_media_list_t mediaListInstance() {
return mediaListInstance; // <- proxy object return null, if use aop
}
}
Custom MediaList Class
public class TestMediaList extends MediaList {
public TestMediaList(LibVlc libvlc, libvlc_instance_t instance) {
super(libvlc, instance);
}
public void xTest(String test){
System.out.println(test);
}
}
Spring Configuration Class
#Configuration
public class PlayerBeanConfig {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
#Resource
public TestMediaList testMediaList(LibVlc libvlc, libvlc_instance_t instance) {
return new TestMediaList(libvlc, instance);
}
}
AOP Configuration Class
#Aspect
public class MediaListAspect {
#Pointcut("execution(* TestMediaList.xTest(..))")
private void anyMethod() {
}
#Around("anyMethod()")
public Object lockAndUnlock(ProceedingJoinPoint joinPoint) throws Throwable {
Object object = joinPoint.proceed();
return object;
}
}
Test Code
public static void main(String[] args) {
boolean b = new NativeDiscovery().discover();
if (b) {
springContext = new AnnotationConfigApplicationContext(PlayerBeanConfig.class);
String[] kkk = new String[]{};
TestMediaList list = springContext.
getBean(TestMediaList.class, LibVlc.INSTANCE, LibVlc.INSTANCE.libvlc_new(kkk.length, kkk));
System.out.println(list.mediaListInstance()); // <- proxy object return null
} else {
logger.error("Cannot find vlc lib, exit application");
}
}
I try to single step tracking, when TestMediaList the build is complete. MediaListInstance () of the method to return to normal values, but when the spring returns to the proxy object, null is returned. At the same time, I also try to return the value correctly if you don't use AOP.
Therefore, I determine the basic problem in AOP dynamic proxy, but I don't know why, did not previously encountered such a situation.
Minimal example
all class in package : vod.demo
TargetClass
public class TargetClass {
private String returnValue;
public TargetClass() {
this.returnValue = "Hello World";
}
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
}
Aspect Class
#Aspect
public class AspectClass {
#Pointcut("execution(* vod.demo.TargetClass.*(..))")
private void targetMethod() {
}
#Around("targetMethod()")
public Object aroundTarget(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("AspectClass.aroundTarget();");
return joinPoint.proceed();
}
}
Spring Config Class
#Configuration
#EnableAspectJAutoProxy
#Import(AspectClass.class)
public class SpringConfig {
#Bean
public TargetClass target() {
return new TargetClass();
}
}
Client Class
public class Client {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
TargetClass target = context.getBean(TargetClass.class);
System.out.println("Client invoke:" + target.test()); // <- output null
}
}
This is a combination of potentially unexpected behaviors. First, Spring uses CGLIB to proxy your beans for AOP. CGLIB proxies are instances of a dynamic subtype of your class that delegate all method calls to a real instance of your class. However, even though the proxy is of a subtype, its fields are not initialized (ie. your TargetClass super constructor is not invoked). A lengthier explanation can be found here.
Additionally, your method
public final libvlc_media_list_t mediaListInstance() {
return mediaListInstance; // <- proxy object return null, if use aop
}
or
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
are final. CGLIB therefore cannot override them to delegate to the real instance. This would be hinted at in Spring logs. For example, you would see
22:35:31.773 [main] INFO o.s.aop.framework.CglibAopProxy - Unable to proxy method [public final java.lang.String com.example.root.TargetClass.test()] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
Put all of the above together and you get a proxy instance where the field is null and where the proxy cannot delegate to the real instance's method. So your code will actually invoke
public final String test() {
System.out.println("TargetClass.test();");
return returnValue;
}
for an instance where the returnValue field is null.
If you can, change your method, remove the final modifier. If you can't, you'll have to rethink your design.

Categories

Resources