Spring `JpaRepository` to be used only in test scope - java

I have a JpaRepository, that looks like
#Repository
public interface CustomRepository extends JpaRepository<EntityType, Integer> {
// Methods
}
which could possibly have queries that would run for long, in which case I need to enforce a timeout. I have successfully added the timeout-related configuration (the connection pool being used is Druid, if that matters) and now I want to test it in a unit test. I am using the following method in my JpaRepository<T, ID> interface.
#Query(value = "SELECT benchmark(:count, MD5('3094803'))", nativeQuery = true)
void run(#Param("count") Long count);
This method runs successfully and demonstrates the expected behavior. However, given that this method will run longer as the value given to parameter count becomes larger, having this in the production code, just for the sake of testing the timeouts, bothers me to my core, as this might end up being a vulnerability that could be leveraged to launch a denial attack.
So to the question, is some way I can use this exact method in my test scope, without having that going in the production code?

Turns out, it's not that complicated. Given that this project is running on Spring, I can have an extension of the above repository in my test sources, as follows.
package com.project.package.repo;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
#Repository
public interface TimedCustomRepository extends CustomRepository {
#Query(value = "SELECT benchmark(:count, MD5('3094803'))", nativeQuery = true)
void run(#Param("count") Long count);
}
As I have JUnit4, I can have a test class which will run on Spring boot, like follows.
package om.project.package.repo;
import com.github.database.rider.spring.api.DBRider;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.test.context.junit4.SpringRunner;
#SpringBootTest
#RunWith(SpringRunner.class)
#DBRider(dataSourceBeanName = "primaryDataSource") //Data source wiring; Not that important.
public class TransactionHistoryJpaRepoTest {
#Autowired //---(1)
private TimedCustomRepository timedCustomRepository;
#Test(expected = JpaSystemException.class)
public void whenQueryTimeoutOccurs() {
timedCustomRepository.run(100000000L);
}
}
The property at (1) will be wired using the repository bean which we have created above, and this test will execute as expected. Given the bean TimedCustomRepository extends CustomRepository, the data source configuration and everything will be the same. Most importantly, since this method with a long running query is now only on the test scope, it will not have any impact beyond the test scope.

Related

#Value not Injecting ANY value

I'm learning how to create a RESTful API with Springboot, and the #Value tag is not injecting values from application.properties, nor is it injecting values specified in the tag itself. I have my project structured as such:
api
config
controllers
model
services
SpringApplication.java
resources
application.properties
Strangely, this behavior only seems to occur within files located in my "services" folder. The #Value tag works as expected in files located in my "controllers" folder. Below are examples of what I am doing:
#Value("${var}")
String variable
"var" is defined in application.properties as var=some_stringbut variable is still initialized as 'null'
#Value("I am directly assigning a value to this variable, but it still comes out null")
String variable
I believe I am using the correct import: import org.springframework.beans.factory.annotation.Value.
At first I just thought the "services" folder was blind to the directory where application.properties is located, but after trying to directly inject values, I'm not so sure what to think.
Edit
All of the classes in the services folder are annotated with #Service and nothing else. Below is what the class looks like. I've opted to leave out implementations of the methods, other variables, and irrelevant imports. The code/methods all work as expected when hard-coding the variables. My focus is the #Value tag.
package myapi.api.services;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
#Service
public class MyService {
#Value("${var}")
String variable;
public List<Data> getData() {
return new ArrayList<Data>();
}
public void postData() {
}
Edit 2
Below is the APIController class, stored in the "controllers" folder. Again, I've opted to leave out irrelevant methods/imports/variables. I would also like to note, that the #Value tag works as expected in this class.
package myapi.api.controllers;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import myapi.api.services.MyService;
import lombok.RequiredArgsConstructor;
#RestController
#RequestMapping("api")
#RequiredArgsConstructor
public class APIController {
#Autowired
private final static MyService myService = new MyService();
#GetMapping("/getdata")
public List<Data> getData() {
return myService.getData();
}
}
#Autowired
private final static MyService myService = new MyService();
Three issues:
First, you cannot have a new operator. Spring controls the lifecycle of your class instances. It will call new for you in the background. Remove the entire new operator stanza.
Next: your your field cannot be final. After construction of the class, Spring will need to modify that field with a proxy. Remove the final declaration;
Finally: your field cannot be static. static variables have a certain lifecycle with the JVM, and you need to let the Spring framework manage your lifecycle. remove the static operator.
The correct declaration should be:
#Autowired
private MyService myService;

Purpose of Service Interface Class in Spring Boot

My question is regarding the use of the interface class. I am fairly new to Spring so please bear with me if this is overly simple.
First of all, what is the point of having an IBoxService interface here when you could just declare the find all in BoxService. Secondly, in the controller how is IBoxService being used. Meaning, we are calling IBoxService.findAll(). But, how is this being tied to the BoxService class. What if multiple service classes implemented IBoxService? Is this a java thing or a Spring injection thing. Thanks.
package com.xyz.service;
import com.xyz.model.Box;
import java.util.Set;
public interface IBoxService {
Set<Box> findAll();
}
package com.xyz.service;
import com.xyz.model.Box;
import com.xyz.repository.BoxRepository;
import java.util.Set;
import org.springframework.stereotype.Service;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
#Service
#AllArgsConstructor
#Slf4j
#Transactional
public class BoxService implements IBoxService {
#Autowired
private BoxRepository boxRepo;
#Override
public Set<City> findAll() {
return (Set<City>) repository.findAll();
}
}
package com.xyz.controller;
import com.xyz.model.Box;
import com.xyz.service.IBoxService;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/api/box")
public class BoxController {
#Autowired
private IBoxService boxService;
#GetMapping
public ResponseEntity<Set<Boxes>> allBoxes() {
return (Set<Box>) boxService.findAll();
}
}
There are various reasons why Service layer interfaces are created. The first and most important reason is testability. You can create mocks of service interface and test your code easily, if you cannot create mocks using a mocking library then you can create test stubs.
One more reason is, we can achieve loose coupling between Controller and Service layer. Suppose you want to entirely change the implementation of service, you can create new service implementation and inject that implementation by injecting new bean by qualifier name
Please understand basic Java and use of interface . Spring boot is just abstraction over Java hence all the basic concepts applies as it is.
Coming back to your questions IBoxService is a interface which allows to inject required implementation of it at controller level. As of now only implementation of IBoxServic is BoxService hence it is getting injected automatically. In case you have multiple implementations you need to use qualifier annotation to specify kind of implementation you need to inject. Or you can create object bu yourself using class names
Consider below:
IBoxService is implemented by two classes BoxService and TiffinBoxService
Now in controller you can inject implementation which you want. Which allow us to achieve principle of interface which is hide internal details.
User which is controller in this case doesn't need to know which class is being use internally as we are using reference of interface.
List interface is best example which has ArrayList and LinkedList as implementation classes.
Hope it is useful !!

Running Tests with MockitoJUnitRunner fails verify asserts

Is there a way to mock a Repository without the #RunWith(MockitoJUnitRunner) annotation on the class?
I have a test that passed without the annotation but fails with it. Without it, my repo test doesn't work. It's a catch 22.
When I use that annotation, my when() methods in my tests no longer stub behavior, mocks do nothing, and despite setting break ppoints and those breakpoints being hit (indicating the line/method is run), verify(..., times(x)) statements say the mocked object never interacted with that method. I've been pulling my hair out on why using the #RunWith(MockitoJUnitRunner) annotation would make the most simple parts of Mockito not work.
I can't find any threads asking about this but maybe someone knows better keywords to use. Does this sound like a known issue?
Here is my test:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
// toggling this below annotation is the source of grief.
//#RunWith(MockitoJUnitRunner.class)
public class LoadEditEntityChangeLogServiceImplTest {
#InjectMocks
private ServiceImpl serviceMock;
#Mock
private EditStepRepository editStepRepository;
#Mock
private EditMapper editMapper;
#Before
public void init() {
initMocks(this);
}
#Test // when the RunWith is commented out, this passes. When it is not, the test fails the verify assert.
public void mapEditEntityFromAction_Test() {
EditDTO editDTO = Mockito.mock(EditDTO.class);
when(editDTO.getSysNum()).thenReturn((long)7334);
EditEntity editEntity = new editEntity();
editEntity.setSysNum(editDTO.getSysNum());
when(editMapper.mapToEntity(eq(editDTO))).thenReturn(editEntity);
editEntity response = serviceMock.mapEditEntityFromAction(editDTO);
verify(loadEditMapper, times(1)).mapToEntity(eq(loadEventDTO));
assertEquals(loadEventDTO.getSystemNumber(), response.getSystemNumber());
}
#Test // this will fail without the #RunWith as the mocked repo will be null and throws NullPointerException when used.
public void updateConvertedEventSegment_Test() {
EditEntity editEntity = new EditEntity();
EditStepEntity editStepEntity = new EditStepEntity();
editEntity.setEditStep(editStepEntity);
doReturn(editStepEntity).when(editStepRepository).save(any());
serviceMock.updateEditStep(editEntity);
verify(editEntity, times(1)).getEditStep();
verify(editStepRepository, times(1)).save(eq(editStepEntity));
}
}
You should understand what does this runner actually do:
Basically it allows injecting mocks (prepared by mockito with Mockito.mock(...) ) into the test fields annotated with #Mock. In the question, since you've commented out the runner, all these fields will be null.
When you annotated something with #InjectMocks - it will inject the mocks into the fields of the object of type of the annotated reference.
One more point to clarify here: MockitoAnnotations.initMocks(this) will do the same as the "runner" so no need to include both (you should use initMocks if you can't use the runner for some reason, like if there is already another runner that must be used)
Now, you ask:
Is there a way to mock a Repository without the #RunWith(MockitoJUnitRunner) annotation on the class?
The answer is - yes, you can, in fact you don't have to use the runner, sometimes its more convenient.
So, assuming you really use this runner, the real question is what exactly do you mean by "my repository doesn't work". Does this mean that there exists a reference in the service that points of this repository and its null?
Does it mean that there is a mock of repository but when you execute the call "under the test" the mock is different?
You don't show it in the code, but I assume you have some like this:
public class ServiceImpl {
private final EditStepRepository editStepRepository;
public ServiceImpl(EditStepRepository editStepRepository) {
this.editStepRepository = editStepRepository;
}
...
}
But if so, once you create a mock (and indeed there should be a mock injected into the ServiceImpl class (check this out with debugger or something), There should be expectatations specified on the repository, usually there should be code like this in the test:
Mockito.when(editStepRepository.doSomething(...)).thenReturn(...)
You haven't placed any of these lines, that why it doesn't work.
But all-in-all since the question contains many uncertain technicalities like this, I can't tell more than that other that speculating...

Is there a way for creating a spring context which can run before all of my junit unit tests which are on different classes? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
Sorry I did not research this issue deeply on the internet or on SO. So down voting is welcome. After all I have a feeling this may be a dump question. However I am giving a shot.
I have a project which will contain all of the unit tests. All of the unit tests require a setup which basically creates a jndi namespace. I am doing this with #Before tag on each of my unit test class. So I am doing lots of copy paste which is irritating me a little. Is there a way of creating a singleton class which creates this jndi namespace for all of my unit tests possibly with spring or any other way.
Thanks for the M. Deinum sollution. If he posted the answer I would accept it.
I created a master class like this
import java.io.IOException;
import java.sql.SQLException;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.naming.NamingException;
public class JndiInit{
#PostConstruct
public void init() throws IOException, SQLException, NamingException{
System.out.println("Mastersetup for initializing jndi namespace");
}
#PreDestroy
public void tearDown(){
System.out.println("Tear down");
}
}
My unit tests uses a spring context
Test 1 :
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/testContext.xml")
public class Test1{
#Test
public void test(){
System.out.println("test 1");
}
}
And Test2
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/testContext.xml")
public class Test2 {
#Test
public void test(){
System.out.println("test 2");
}
}
And my spring context is like :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="tr.com.mhrs.test.base.jndifactory.JndiInit">
</bean>
</beans>
It successfully achieved what I want.
Mastersetup for initializing jndi namespace
test 1
test 2
Tear down
Thanks guys.
You can implement the JNDI logic in a JNDITestExecutionListener class which implements org.springframework.test.context.TestExecutionListener and annotate your tests with the listener as follows
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners(JNDITestExecutionListener.class)
Another option is to create a JUnit rule for this.
Create an abstract class which has a method which would do your JNDI setup.
EDIT: On second thoughts, this need not be an abstract. It can be, if you want to enforce some setup semantics on all your test classes, but it doesnt have to be.
Annotate this method with a #BeforeClass.
Now, extend all your Unit test classes with this parent class. Something like this
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:conf/spring/test-context.xml")
public abstract class AbstractParent{
#BeforeClass
setupJNDI(){
....
}
}
public class MyTestClass
extends AbstractParent{
#Test
public void myTestMethod(){
....
}
}
About #BeforeClass -
Sometimes several tests need to share computationally expensive setup (like logging into a database). While this can compromise the independence of tests, sometimes it is a necessary optimization. Annotating a public static void no-arg method with #BeforeClass causes it to be run once before any of the test methods in the class. The #BeforeClass methods of superclasses will be run before those the current class.

Mockito Passes but Code Coverage still low

package com.fitaxis.test;
import java.sql.SQLException;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.mockito.Mockito.*;
import com.fitaxis.leaderboard.LeaderBoard;
public class LeaderBoardTests {
#Test
public void TestThatDataIsSavedToTheDatabase()
{
LeaderBoard leaderBoard = mock(LeaderBoard.class);
//doNothing().doThrow(new RuntimeException()).when(leaderBoard).saveData();
when(leaderBoard.saveData()).thenReturn(true);
boolean res = leaderBoard.saveData();
verify(leaderBoard).saveData();
Assert.assertTrue(res);
}
}
I have used mockito to mock a class, but when I use code coverage it does not detect that the method as been called. Am I doing something wrong? Please help!
It looks like you're mocking out the only call you're making to production code.
In other words, your test says:
When I call saveData(), fake the result to return true
Now call saveData() - yay, the result was true!
None of your production code is being calls at all, as far as I can see.
The point of mocking is to mock out dependencies from your production class, or (sometimes, though I prefer not to) to mock out some methods of your production class that the code you're actually testing will call.
You should probably be mocking out the dependencies of Leaderboard rather than Leaderboard itself. If you must mock out saveData(), you should be testing the methods that call saveData()... check that they save the right data, that they act correctly when saveData() returns false, etc.
if i understand your question correctly :
because you are mocking LeaderBoard. that means that you are not testing it.
if you want to test LeaderBoard, you should test the actual class not the mocked one.
let say you want to test class A but this class depends on B and B is a bit difficult to instantiate in testing environment(for any reason). in such cases you can mock B.
but here is your case you are mocking class A itself. that means you are not testing anything.
add runner class as MockitoJUnitRunner, please refer the below sample code
import org.mockito.junit.MockitoJUnitRunner
#RunWith(MockitoJUnitRunner.class)
public class MockitTesterClass{
#Mock
private TestService testServiceMock;
}
now the code coverage will increase

Categories

Resources