I am investigating the use of Spring Data Rest (2.0.1.RELEASE and Spring 4.0.2.RELEASE), and have written a simple service. I have also written a simple test class (see below) using DbUnit.
Unfortunately when I run the tests only the findAll method passes. If I comment out the findAll method then the findInvestigationalProductById passes and directLink fails. If I then comment out findInvestigationalProductById then directLink passes.
None of these methods changes data state, so I would like to know if there is some configuration I have overlooked that can cause this behaviour.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/com/perceptive/ctms/core/tests-context.xml"})
#WebAppConfiguration
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class,
DbUnitTestExecutionListener.class })
#DatabaseSetup("investigational-products-data.xml")
public class InvestigationalProductTests {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
MockitoAnnotations.initMocks(this);
}
#Test
public void findAll() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct", hasSize(3)));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[0].investigationalProductCode", is("ACTIVE1")));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[1].investigationalProductCode", is("ACTIVE2")));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[2].investigationalProductCode", is("ACTIVE3")));
}
#Test
public void directLink() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct/3"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
System.out.println(resultActions);
resultActions.andExpect(jsonPath("$investigationalProductCode", is("ACTIVE3")));
}
#Test
public void findInvestigationalProductById() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/investProduct/search/findInvestigationalProductById?id=3"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/hal+json"));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct", hasSize(1)));
resultActions.andExpect(jsonPath("$_embedded.investigationalProduct[0].developmentName", is("developmentName3")));
}
}
This is a misunderstanding about how #DatabaseSetup works. The problem tests are all dealing with referencing data by a generated id. The API states:
Test annotation which indicates how to put a database into a know
state before tests are run. This annotation can be placed on a class
or on methods. When placed on a class the setup is applied before each
test methods is executed.
which to my mind is a little ambiguous, but additional documentation states:
By default setup will perform a CLEAN_INSERT operation, this means
that all data from tables referenced in the DataSet XML will be
removed before inserting new rows.
i.e. tests should not assume that the database (including any sequence numbers) is put into a clean state, just that the data is clean.
Adding the following code
private static int currentOffset = 0;
private static final int TEST_OFFSET = 3;
/**
* After each test is run DatabaseSetup annotation deletes records
* and inserts fresh ones - this means we need to keep track of the
* current offset
*/
#After
public void offset() {
currentOffset += TEST_OFFSET;
}
(with occasional modifications to currentOffset when testing inserts) can keep track of the current ids.
This does not seems ideal, but I do not know a way of resetting the database to a truly clean state.
Related
I have to create a integration test for a microservice X which downloads, processes and importing csv files from external sftp servers. The whole process is started by a spring boot scheduler task which starts a spring batch job for processing and importing the data. The import process is done by the spring batch writer, which is a restTemplate Repository (so it calls post requests to another microservice Y).
I already managed to mock the sftp server, putting a test file on it and the current integration test is downloading the file. (https://github.com/stefanbirkner/fake-sftp-server-rule/)
My problem is, that the task will be scheduled immediately when the application context starts so there is no trigger like a api call. To get the whole integration test working i have to mock the part where the external microservice Y is called through a restTemplate call. This repository is called in the spring batch writer and this repository is created by a repositoryFactory which is a #Service. The repositoryFactory is injected in the spring batch configuration class.
I already tried to use the #MockBean annotation in the test class as well as in a separate test configuration where i am mocking the create() function of the factory to deliver a repository mock. But at some point it does not work and it delivers still the original object which leads to interupt the import job.
I also tried to use the WireMock library, but also in this case it does not catched any api calls and at some point leads to interrupt the sftp socket. (?)
I hope someone could help me out.
The current test:
#NoArgsConstructor
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ContextConfiguration(classes = {JsonHalConfig.class})
#TestPropertySource(locations = "classpath:application-test.properties")
#TestMethodOrder(MethodOrderer.MethodName.class)
public class ImportIT {
#ClassRule
public static final FakeSftpServerRule sftpServer = new FakeSftpServerRule();
private static final String PASSWORD = "password";
private static final String USER = "username";
private static final int PORT = 14022;
#BeforeClass
public static void beforeClass() throws IOException {
URL resource = getTestResource();
if (resource != null) {
sftpServer.setPort(PORT).addUser(USER, PASSWORD);
sftpServer.createDirectories("/home/username/it-space/IMPORT", "/home/username/it-space/EXPORT");
sftpServer.putFile("/home/username/it-space/IMPORT/INBOX/testFile.csv",
resource.openStream());
} else {
throw new IOException("Failed to get test resources");
}
}
private static URL getTestResource() {
return ImportIT.class.getClassLoader().getResource("testFile.csv");
}
#Test
public void test_A_() throws IOException, RepositoryException {
assertTrue(true);
}
}
I tried following configuration classes
(included in #ContextConfiguration)
#Configuration/#TestConfiguration
public class RepositoryTestConfig {
#Bean
#Primary
public IRepositoryFactory repositoryFactory() {
IRepositoryFactory repositoryFactory = mock(IRepositoryFactory.class);
IRepository repository = mock(IRepository.class);
when(repositoryFactory.create(anyString())).thenReturn(repository);
return repositoryFactory;
}
}
(as static class in the test class)
#TestConfiguration/#Configuration
public static class RepositoryTestConfig {
#MockBean
private IRepositoryFactory repositoryFactory;
#PostConstruct
public void initMock(){
IRepository repository = mock(IRepository.class);
Mockito.when(repositoryFactory.create(anyString())).thenReturn(
repository
);
}
}
UPDATE 27.08.2021
I have a RestConfig #Component where a new RestTemplateBuilder is created. I tried to #MockBean this component to deliver a RestTemplateBuilder Mock and injected a MockRestServiceServer object to catch outgoing api calls. But unfortunately it does not work as aspected. Am i missing something? I also tried to create a "TestRestController" to trigger the scheduling of the task but it never delivers the mock...
I normally use #MockBean directly inside my test classes and inject the dedicated (but mocked) repository directly there and not create it inside the test configuration. I also add the test configuration class by #ContextConfiguration so it is loaded in current test context.
Inside my tests I am just using mockito the standard way and prepare the mocked parts as wanted for the dedicated test method.
Here an example snippet:
// ... do some imports ...
#RunWith(SpringRunner.class)
#ContextConfiguration(classes= {XYZSomeWantedClazz.class, DemoXYZMockTest.SimpleTestConfiguration.class})
#ActiveProfiles({Profiles.TEST})
public class DemoXYZMockTest {
//...
#MockBean
private DemoRepository mockedDemoRepository;
// ...
#Test
public void testMethodName() throws Exception{
/* prepare */
List<WantedEntityClazz> list = new ArrayList<>();
// add your wanted data to your list
// apply to mockito:
when(mockedDemoRepository.findAll()).thenReturn(list);
/* execute */
// ... execute the part you want to test...
/* test */
// ... test the results after execution ...
}
#TestConfiguration
#Profile(Profiles.TEST)
#EnableAutoConfiguration
public static class SimpleTestConfiguration{
// .. do stuff if necessary or just keep it empty
}
}
For a complete (old Junit4) working test example please take a look at:
https://github.com/mercedes-benz/sechub/blob/3f176a8f4c00b7e8577c9e3bea847ecfc91974c3/sechub-administration/src/test/java/com/daimler/sechub/domain/administration/signup/SignupAdministrationRestControllerMockTest.java
Hello every one I need to write unit tests for my methods. I'm having a bit of trouble because I'm new to JUnit. I need to write a test for this method.
this is my method
#Override
public Long countSellingOrdersInQueue(String principal) {
List<String> states = Arrays.asList(PENDING.name(), REGULARIZED.name());
return orderRepository.countByArticleUserIdAndStateIn(principal, states);
}
I try but i'm blocked and this is my result
P.S. test is passed but I don't understand if my test is true
#MockBean
private OrderRepository orderRepository;
private String principal ;
#Test
public void countSellingOrdersInQueueTest(){
orderService.countSellingOrdersInQueue(principal);
List<String> states = Arrays.asList(PENDING.name(), REGULARIZED.name());
orderRepository.countByUserIdAndStateIn(principal,states);
}
In your case, it is just the unit test, you need not use #MockBean, as it loads the context. Unit tests are meant to be run faster, using #MockBean, will load the context and takes time to complete the test. Here is the suggestion of when to use #Mock and when to use #MockBean.
As Maxim said, there were no assertions in the test. That was the reason why the tests weren't failing.
Few things to keep in mind while writing the test.
Tests are considered as documentation for the code, it should be more readable in such a way it makes others to understand the code.
As said before, unit tests are for giving faster feedback
Have AAA (Arrange, Act, Assert) structure in tests. More info here
Here is the code:
public class OrderServiceTest {
#InjectMocks
private OrderService orderService;
#Mock
private OrderRepository orderRepository;
#Before
public void setUp() throws Exception {
initMocks(this);
}
#Test
public void countSellingOrdersInQueueTest(){
when(orderRepository.countByArticleUserIdAndStateIn(any(), any())).thenReturn(1L);
String principal = "dummyString";
Long actualCount = orderService.countSellingOrdersInQueue(principal);
List<String> expectedStates = Arrays.asList("State 1", "State 2");
assertThat(actualCount, is(1L));
verify(orderRepository).countByArticleUserIdAndStateIn(principal, expectedStates);
}
}
Test passes because you don't have any assertion, which checks result. You just invoke methods which executes without exception.
Simple test example:
#Test
public void test() {
assertEquals(true, true);
}
In your case test will be look likes:
#Test
public void countSellingOrdersInQueueTest(){
orderService.countSellingOrdersInQueue(principal);
List<String> states = Arrays.asList(PENDING.name(), REGULARIZED.name());
orderRepository.countByUserIdAndStateIn(principal,states);
assertEquals(10, orderRepository.countByUserIdAndStateIn(principal,states));//10 replace to expectetion count
//add some more checks
}
I'm woking on EJB Project, using JPA to query data. Now, I create unit test and use mockito to mock data. There is a function that I call data from criteria builder, and it's called from #PostConstruct. So if result is empty, then it will throw NoResultException. However, I am unable to run unit test to test it. Take a look on source code below:
For class RefdataUpdateDaoImpl
public class RefdataUpdateDaoImpl{
public RefdataUpdate getSingleUpdate() {
CriteriaBuilder cb = getCriteriaBuilder();
CriteriaQuery<RefdataUpdate> query = cb.createQuery(RefdataUpdate.class);
Root<RefdataUpdate> rootEntry = query.from(RefdataUpdate.class);
CriteriaQuery<RefdataUpdate> all = query.select(rootEntry);
TypedQuery<RefdataUpdate> allQuery = getEntityManager().createQuery(all);
return allQuery.getSingleResult();
}
}
In RefDataCacheBean
#PostConstruct
private void postConstruct() throws Exception{
cachedUpdateTs = RefdataUpdateDaoImpl.getLastUpdate();
}
This is unit test
#Test(expected = NoResultException.class)
public void testExistingRefDataUpdate() throws NoResultException{
update.deleteRefDataUpdate();
refdataServiceBean.getLastUpdate();
}
So in unit test, it loads data from dataset xml. So when I run test, it supposes to throw NoResultException and test passes, but test fails and console log no entity data found.
Please help to create unit test in this case, when function's called from #PostConstruct.
Trace Logs:
javax.ejb.EJBException: javax.persistence.NoResultException: No entity found for query
Thank you and any comments will be appreciated.
Obviously the NoResultException is nested in a EJBException so your test code should be:
#Test(expected = EJBException.class)
public void testExistingRefDataUpdate() throws NoResultException{
update.deleteRefDataUpdate();
refdataServiceBean.getLastUpdate();
}
we are developing an application using spring mvc framework. I have given all the classes below, please suggest how to write a junit test case for the below scenario.
I want to write a junit test case for the validateAccountInformation(requestDTO) method which is called in validateAccount(..) method of LPAValidator.java class. Below is my junit test case followed by the java classes. Actual call goes from the LPAController.java as shown in the below code.
LPAControllerTest.java
#Test(groups = "manual")
public void submitRequestForLPAAccountTest()
{
// businessCalendar.nextBusinessDay(
// LocalDateHelper.today(), LPAConstants.TWENTY_BUSSINESS_DAYS)
//i want to write the test case for the above commented logic,
//if business days is not equal to twenty days, test should fail.
}
LPAController.java
#RequestMapping(value = "/lpa/{accNumber}/spread, method = RequestMethod.GET)
public #ResponseBody LPAResponseDTO accountSearch(#RequestBody final LPARequestDTO clientrequestBody,
#PathVariable final String accNumber, final HttpServletResponse response)
{
//some logic goes here
final LPAAccountResponse domainResponse = service.submitRequestForLPAAccount(requestBody);
}
LPAServiceImpl.java
#PermitAll
#NonTransactional
public LPAResponse submitRequestForLPAAccount(final LPARequest requestDTO)
{
return lpaRepository.submitRequestForLPAAccount(requestDTO));
}
LPARepository.java
#PermitAll
#NonTransactional
public LPAResponse submitRequestForLPAAccount(final LPARequest requestDTO)
{
//some logic
lpaValidator.validateAccount(requestDTO);
//some logic
}
LPAValidator.java -- java class for validations
#component
class LPAValidator{
#Inject
private BusinessCalendar businessCalendar;
void validateAccount(final LPARequest requestDTO) throws Exception {
try {
validateAccountInformation(requestDTO);
} catch(Exception e){
}
}
private void validateAccountInformation(final LPARequest requestDTO) throws Exception{
final accDate lpaAccDate = requestDTO.getLPADate();
final LocalDate twentyBussinessDays = businessCalendar.nextBusinessDay(
LocalDateHelper.today(), LPAConstants.TWENTY_BUSSINESS_DAYS); //i want to write
//test case for this line of code, if business days given is more than twenty test should fail.
//some logic here
}
Please suggest what needs to be added in LPAControllerTest.java to test the nextBusinessDay(..) as discussed above.
You're trying to write an integration test in which your controller is called, which then calls all the subclasses until the validator is triggered. That is not a traditional 'unit test'.
A traditional unit test would just test the validator straight up, and nothing more.
Nevertheless, when writing an integration test, spring documentation to the rescue
In short, it'll require you to create an applicationcontext with all the necessary scaffolding, and then use a mockMvc call to do a GET on the created application.
If you want to test the validator, use simple mocking framework:
See [http://mockito.org]
Gives you something like this:
#Mock BusinessCalendar businessCalendarMock;
#Mock LPARequest mockRequest;
#Mock accDate mockDate;
#Mock LocalDate mockLocalDate;
#InjectMocks LPAValidator lpaValidator = new LPAValidator();
#Test public void testValidateAccount() {
when(mockRequest.getLPAdate()).thenReturn(mockDate);
when(businessCalendar.nextBusinessDay(LocalDateHelper.today(),LPAConstants.TWENTY_BUSSINESS_DAYS).thenReturn(mockLocalDate);
// continue your test from here
lpaValidator.validateAccount( mockRequest);
verify(businessCalendar).nextBusinessDay(LocalDateHelper.today(),LPAConstants.TWENTY_BUSSINESS_DAYS);
// although if the use of mockLocalDate is integral to your code, it'll probably show before and no verify is necessary;
I am making Test of My classes so I am inserting so many data for to test my code.
So I am thinking to make some mechanism of savepoint and rollback in DB.
I am using postgresql as DB sever.
Following is my code for test :
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("file:src/main/webapp/WEB-INF/ls-dispatcher-servlet.xml")
public class AddBindingProcessorTest extends IntegrationTestBase {
#Autowired
private AddBindingProcessor processor;
public AddBindingProcessorTest(){
}
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void add() throws Exception {
AddBinding command;
command = new AddBinding();
command.setId(50l);
command.setBindingName("bindingtest1");
command.setBindingPrice((double)253);
BindingTypeResponse response = (BindingTypeResponse)processRequest(command);
System.out.println("from addbindingprocessor test "+response.getBindingName());
}
}
Here I am setting value through command object and passing to ProcessRequest() Method that will store data inside DB using hibernate.
Still I have to write assert in my testProcess() method that will check data is correct or not ?
So my question is that I when this transaction starts in setUp() method one savepoint should be created and then testProcess() method will be executed and assert check for the data that they are correct or not and then in tearDown() method I want to rollback to savepoint that is set in setUp() method.
So how to do so ? If Anyone can just guide me that what I ll have use and how to move forward then I ll learn that thing and go by myself.
I just want guidance about it that what I ll have to use and where ?
Thank You All.
If I get you right, you can just use the
#TransactionConfiguration(defaultRollback = true)
annotation below your #ContextConfiguration annotation.
This will rollback the changes in your tests after every run.
user3145373 pointed out, that the attribute transactionManager="context bean transaction manager" in #TransactionConfiguration needed to be set also.
It is part of the spring-test lib.