I need to write a unit test for solr SearchComponent (SearchComponent.process ()).
How could I do that? Can I use SolrTestCaseJ4 or another way?
I am currently using SolrTestCaseJ4...
I am currently using SolrTestCaseJ4...
public class SearchComponentTest extends SolrTestCaseJ4 {
#BeforeClass
public static void beforeClass() throws Exception {
initCore("collection1/conf/solrconfig.xml", "collection1/conf/schema.xml", "src/test/resources/");
}
#Test
public void testPrepare() throws IOException {
MySearchComponent component = new MySearchComponent();
List<SearchComponent> components = new ArrayList<>();
components.add(component);
SolrQueryRequest req;
ResponseBuilder rb;
req = req("q", "*:*");
rb = new ResponseBuilder(req, new SolrQueryResponse(), components);
component.process(rb);
}
}
and my SearchComponent:
public class MySearchComponent extends SearchComponent {
public void process(ResponseBuilder rb) throws IOException {
....
SolrQueryRequest req = rb.req;
SolrQueryResponse rsp = rb.rsp;
SolrParams params = rb.req.getParams();
SchemaField keyField = rb.req.getCore().getLatestSchema().getUniqueKeyField();
String core = rb.req.getCore().getName();
SolrIndexSearcher searcher = req.getSearcher();
QueryCommand cmd = rb.createQueryCommand();
QueryResult result = new QueryResult();
searcher.search(result, cmd);
rb.setResult(result);
BasicResultContext ctx = new BasicResultContext(rb, rb.getResults().docList);
rsp.add("response", ctx);
...
}
...
}
But i have NullPointerException on this line:
QueryCommand cmd = rb.createQueryCommand();
Thank you for your help!
Related
The problem is the following. I have several reports that I want to mock and test with Mockito. Each report gives the same UnfinishedVerificationException and nothing that I tried so far worked in order to fix the issue. Example of one of the reports with all parents is below.
I changed any to anyString.
Change ReportSaver from interface to abstract class
Add validateMockitoUsage to nail the right test
Looked into similar Mockito-related cases on StackOverflow
Test:
public class ReportProcessorTest {
private ReportProcessor reportProcessor;
private ByteArrayOutputStream mockOutputStream = (new ReportProcessorMock()).mock();
#SuppressWarnings("serial")
private final static Map<String, Object> epxectedMaps = new HashMap<String, Object>();
#Before
public void setUp() throws IOException {
reportProcessor = mock(ReportProcessor.class);
ReflectionTestUtils.setField(reportProcessor, "systemOffset", "Europe/Berlin");
ReflectionTestUtils.setField(reportProcessor, "redisKeyDelimiter", "#");
Mockito.doNothing().when(reportProcessor).saveReportToDestination(Mockito.any(), Mockito.anyString());
Mockito.doCallRealMethod().when(reportProcessor).process(Mockito.any());
}
#Test
public void calculateSales() throws IOException {
Map<String, Object> processedReport = reportProcessor.process(mockOutputStream);
verify(reportProcessor, times(1)); // The line that cause troubles
assertThat(Maps.difference(processedReport, epxectedMaps).areEqual(), Matchers.is(true));
}
#After
public void validate() {
Mockito.validateMockitoUsage();
}
}
Class under test:
#Component
public class ReportProcessor extends ReportSaver {
#Value("${system.offset}")
private String systemOffset;
#Value("${report.relativePath}")
private String destinationPathToSave;
#Value("${redis.delimiter}")
private String redisKeyDelimiter;
public Map<String, Object> process(ByteArrayOutputStream outputStream) throws IOException {
saveReportToDestination(outputStream, destinationPathToSave);
Map<String, Object> report = new HashMap<>();
try (InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
InputStreamReader reader = new InputStreamReader(inputStream)) {
CSVReaderHeaderAware csvReader = new CSVReaderFormatter(outputStream).headerAware(reader);
Map<String, String> data;
while ((data = csvReader.readMap()) != null) {
String data = data.get("data").toUpperCase();
Long quantity = NumberUtils.toLong(data.get("quantity"));
report.put(data, quantity);
}
}
return report;
}
}
Parent class:
public abstract class ReportSaver {
public void saveReportToDestination(ByteArrayOutputStream outputStream, String destinationPathToSave) throws IOException {
File destinationFile = new File(destinationPathToSave);
destinationFile.getParentFile().mkdirs();
destinationFile.delete();
destinationFile.createNewFile();
OutputStream fileOutput = new FileOutputStream(destinationFile);
outputStream.writeTo(fileOutput);
}
}
Mock:
public class ReportProcessorMock implements GeneralReportProcessorMock {
private static final String report = ""; // There can be some data in here
#Override
public ByteArrayOutputStream mock() {
byte[] reportBytes = report.getBytes();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(reportBytes.length);
outputStream.write(reportBytes, 0, reportBytes.length);
return outputStream;
}
}
When you verify, you verify a particular public method of the mock:
verify(reportProcessor, times(1)).process(mockOutputStream);
or use a wildcard if appropriate:
verify(reportProcessor, times(1)).process(any(ByteArrayOutputStream.class));
I have the method:
public HTTPResult get(String url) throws Exception{
try {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return new HTTPResult(response.getBody(), response.getStatusCode().value());
}
catch (ResourceAccessException e) {
String responseBody = e.getCause().getMessage();
JSONObject obj = new JSONObject(responseBody);
return new HTTPResult(obj.getString("responseBody"), Integer.parseInt(obj.getString("statusCode")));
}
}
I want to do unit testing for it and i am not sure how to proceed:
public class MockHttpServerTest {
private static final int PORT = 51234;
private static final String baseUrl = "http://localhost:" + PORT;
private MockHttpServer server;
private SimpleHttpResponseProvider responseProvider;
private HttpClient client;
#Before
public void setUp() throws Exception {
responseProvider = new SimpleHttpResponseProvider();
server = new MockHttpServer(PORT, responseProvider);
server.start();
client = new DefaultHttpClient();
}
I am getting RED for MockHttpServer & SimpleHttpResponseProvider which should be part of org.apache.wink.client.*; which i am importing. so why do i have red ones? is there some simple way to unit test it?
HTTPResult return me response code and message.
I"m given a requirement on how to test HTTP website without UI. Let says, we have a google website search functionalities (Not Web Services) and I need to test it. How to start? Can anyone give some example (JUnit)(Get/Post Method) for me to start this project. I tried reading the official documentation but found nothing about it. Thanks in advance.
You can do it with the following snippet
public class Searcher {
public String search(String searchUrl, String searchWord) throws IOException, URISyntaxException {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
URIBuilder builder = new URIBuilder(searchUrl);
builder.setParameter("search_term", searchWord);
HttpGet request = new HttpGet(builder.build());
HttpResponse httpResponse = httpClient.execute(request);
return convertResponseToString(httpResponse);
}
}
private String convertResponseToString(HttpResponse response) throws IOException {
try (Scanner scanner = new Scanner(response.getEntity().getContent(), "UTF-8")) {
String responseString = scanner.useDelimiter("\\Z").next();
return responseString;
}
}
}
public class SearcherTest {
#Rule
public WireMockRule wireMockRule = new WireMockRule(options().dynamicPort());
#Test
public void searchTest() throws IOException, URISyntaxException {
String searchWord = "something";
String expectedResult = "Your expected result";
stubFor(get(urlPathEqualTo("/search"))
.withQueryParam("search_term", equalTo(searchWord))
.willReturn(aResponse()
.withBody(expectedResult)));
Searcher searcher = new Searcher();
String searchResult = searcher.search("http://localhost:" + wireMockRule.port() + "/search", searchWord);
verify(getRequestedFor(urlPathEqualTo("/search"))
.withQueryParam("search_term", equalTo(searchWord)));
assertEquals(expectedResult, searchResult);
}
}
I am using Mockito to mock queryForObject but I get NPE. Looks like I am setting everything needed.
long identity = getJdbcTemplate().queryForObject( getStatementConfiguration().getStatement( KeyConstants.CLIENT_USER_VENDOR_IDENTITY), Long.class); is where I get NPE.
MUT
public IClientUserVendorDto insert(final IClientUserVendorDto dto) throws DaoException {
try {
String sql1 = getStatementConfiguration().getStatement(KeyConstants.CLIENT_USER_VENDOR_RETRIEVE);
Object args[] = new Object[] {
dto.getClientUserId(),
dto.getVendor().getId(),
dto.getIdentifier(),
Boolean.TRUE,
dto.getCreatedBy(),
dto.getLastModifiedBy()};
//insert
String sql = getStatementConfiguration().getStatement(KeyConstants.CLIENT_USER_VENDOR_INSERT);
getJdbcTemplate().update(sql, args);
//Retrieve
long identity = getJdbcTemplate().queryForObject( getStatementConfiguration().getStatement( KeyConstants.CLIENT_USER_VENDOR_IDENTITY), Long.class);
return (ClientUserVendorDto) getJdbcTemplate().queryForObject(sql1, new Object[] {identity}, new ClientUserVendorRowMapper());
} catch (Exception e) {
String message = "An exception occurred inserting a Client User Vendor.";
IExceptionHandlerResponse r = getExceptionHandler().handleData(e, DaoException.class, message);
if (r.isRethrow()) {
DaoException daoe = (DaoException) r.getThrowable();
throw daoe;
}
throw (DaoException)r.getThrowable();
} finally {
}
}
Junit
public void testInsert() throws Exception {
AppContext.setApplicationContext(applicationContext);
IVendorDto v = new VendorDto();
IClientUserVendorDto userDto = new ClientUserVendorDto();
userDto.setActive(true);
userDto.setClientUserId(new Long(1220));
userDto.setIdentifier("JUnit-ID");
userDto.setVendor(v);
v.setId(new Long(123));
userDto.setCreatedBy("SYSTEM");
userDto.setLastModifiedBy("Junit");
ClientUserVendorDao dao = new ClientUserVendorDao();
dao.setConfiguration(daoConfiguration);
dao.setJdbcTemplate(jdbcTemplate);
BaseJdbcDao baseDao = Mockito.mock(BaseJdbcDao.class);
BaseDao baseDao2 = Mockito.mock(BaseDao.class);
IStatementConfiguration stmtConfiguration = Mockito.mock(IStatementConfiguration.class);
Mockito.when(baseDao.getJdbcTemplate()).thenReturn(jdbcTemplate);
IDaoConfiguration configuration = new DaoConfiguration();
configuration.setStatement(stmtConfiguration);
dao.setConfiguration(configuration);
Mockito.when(baseDao.getJdbcTemplate().queryForObject( Mockito.any(String.class), (RowMapper<Long>) Mockito.any(Object.class))).thenReturn(123L);
userDto = dao.insert(userDto);
}
I found out what was the issue. queryForObject was not returning a long value. So, here is the fix for it.
#Test
public void testInsert() throws Exception {
IClientUserVendorDto iClientUserVendorDto = new ClientUserVendorDto();
iClientUserVendorDto.setClientUserId(new Long(1007));
IVendorDto iVendorDto = new VendorDto();
iVendorDto.setId(new Long(1008));
iClientUserVendorDto.setVendor(iVendorDto);
iClientUserVendorDto.setIdentifier("GW_SYS_USER");
iClientUserVendorDto.setActive(true);
iClientUserVendorDto.setCreatedBy("SYSTEM");
iClientUserVendorDto.setLastModifiedBy("SYSTEM");
JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
ClientUserVendorDao clientUserVendroDao2 = Mockito.mock(ClientUserVendorDao.class);
IDaoConfiguration iDaoConfiguration = Mockito.mock(IDaoConfiguration.class);
IStatementConfiguration iStatementConfiguration = Mockito.mock(IStatementConfiguration.class);
Mockito.when(iDaoConfiguration.getStatement()).thenReturn(iStatementConfiguration);
Mockito.when(iStatementConfiguration.getStatement(Mockito.any(String.class))).thenReturn("JUnit");
Mockito.when(clientUserVendroDao2.getJdbcTemplate()).thenReturn(jdbcTemplate);
Mockito.when(jdbcTemplate.queryForObject(Mockito.anyString(), Matchers.eq(Long.class))).thenReturn(1007L);
ClientUserVendorDao clientUserVendorDao = new ClientUserVendorDao();
clientUserVendorDao.setConfiguration(iDaoConfiguration);
clientUserVendorDao.setJdbcTemplate(jdbcTemplate);
iClientUserVendorDto = clientUserVendorDao.insert(iClientUserVendorDto);
I think my scenario is pretty common. I have a database and I want my Spring MVC app to accept a request in the controller, invoke the DB service to get data and send that data to the client as a CSV file. I'm using the JavaCSV library found here to assist in the process: http://sourceforge.net/projects/javacsv/
I've found several examples of people doing similar things and cobbled together something that looks correct-ish. When I hit the method, though, nothing is really happening.
I thought writing the data to the HttpServletResponse's outputStream would be sufficient, but apparently, I'm missing something.
Here's my controller code:
#RequestMapping(value="/getFullData.html", method = RequestMethod.GET)
public void getFullData(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException{
List<CompositeRequirement> allRecords = compReqServ.getFullDataSet((String)session.getAttribute("currentProject"));
response.setContentType("data:text/csv;charset=utf-8");
response.setHeader("Content-Disposition","attachment; filename=\yourData.csv\"");
OutputStream resOs= response.getOutputStream();
OutputStream buffOs= new BufferedOutputStream(resOs);
OutputStreamWriter outputwriter = new OutputStreamWriter(buffOs);
CsvWriter writer = new CsvWriter(outputwriter, '\u0009');
for(int i=1;i <allRecords.size();i++){
CompositeRequirement aReq=allRecords.get(i);
writer.write(aReq.toString());
}
outputwriter.flush();
outputwriter.close();
};
What step am I missing here? Basically, the net effect is... nothing. I would have thought setting the header and content type would cause my browser to pick up on the response and trigger a file download action.
It seems to be because your Content-type is set incorrectly, it should be response.setContentType("text/csv;charset=utf-8") instead of response.setContentType("data:text/csv;charset=utf-8").
Additionally, if you are using Spring 3, you should probably use a #ResponseBody HttpMessageConverter for code reuse. For example:
In the controller:
#RequestMapping(value = "/getFullData2.html", method = RequestMethod.GET, consumes = "text/csv")
#ResponseBody // indicate to use a compatible HttpMessageConverter
public CsvResponse getFullData(HttpSession session) throws IOException {
List<CompositeRequirement> allRecords = compReqServ.getFullDataSet((String) session.getAttribute("currentProject"));
return new CsvResponse(allRecords, "yourData.csv");
}
plus a simple HttpMessageConverter:
public class CsvMessageConverter extends AbstractHttpMessageConverter<CsvResponse> {
public static final MediaType MEDIA_TYPE = new MediaType("text", "csv", Charset.forName("utf-8"));
public CsvMessageConverter() {
super(MEDIA_TYPE);
}
protected boolean supports(Class<?> clazz) {
return CsvResponse.class.equals(clazz);
}
protected void writeInternal(CsvResponse response, HttpOutputMessage output) throws IOException, HttpMessageNotWritableException {
output.getHeaders().setContentType(MEDIA_TYPE);
output.getHeaders().set("Content-Disposition", "attachment; filename=\"" + response.getFilename() + "\"");
OutputStream out = output.getBody();
CsvWriter writer = new CsvWriter(new OutputStreamWriter(out), '\u0009');
List<CompositeRequirement> allRecords = response.getRecords();
for (int i = 1; i < allRecords.size(); i++) {
CompositeRequirement aReq = allRecords.get(i);
writer.write(aReq.toString());
}
writer.close();
}
}
and a simple object to bind everything together:
public class CsvResponse {
private final String filename;
private final List<CompositeRequirement> records;
public CsvResponse(List<CompositeRequirement> records, String filename) {
this.records = records;
this.filename = filename;
}
public String getFilename() {
return filename;
}
public List<CompositeRequirement> getRecords() {
return records;
}
}
Based on Pierre answer, i did a converter. Here is the full code, that works with any Object passed:
TsvMessageConverter.java
public class TsvMessageConverter extends AbstractHttpMessageConverter<TsvResponse> {
public static final MediaType MEDIA_TYPE = new MediaType("text", "tsv", Charset.forName("utf-8"));
private static final Logger logger = LoggerFactory.getLogger(TsvMessageConverter.class);
public TsvMessageConverter() {
super(MEDIA_TYPE);
}
protected boolean supports(Class<?> clazz) {
return TsvResponse.class.equals(clazz);
}
#Override
protected TsvResponse readInternal(Class<? extends TsvResponse> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
protected void writeInternal(TsvResponse tsvResponse, HttpOutputMessage output) throws IOException, HttpMessageNotWritableException {
output.getHeaders().setContentType(MEDIA_TYPE);
output.getHeaders().set("Content-Disposition", "attachment; filename=\"" + tsvResponse.getFilename() + "\"");
final OutputStream out = output.getBody();
writeColumnTitles(tsvResponse, out);
if (tsvResponse.getRecords() != null && tsvResponse.getRecords().size() != 0) {
writeRecords(tsvResponse, out);
}
out.close();
}
private void writeRecords(TsvResponse response, OutputStream out) throws IOException {
List<String> getters = getObjectGetters(response);
for (final Object record : response.getRecords()) {
for (String getter : getters) {
try {
Method method = ReflectionUtils.findMethod(record.getClass(), getter);
out.write(method.invoke(record).toString().getBytes(Charset.forName("utf-8")));
out.write('\t');
} catch (IllegalAccessException | InvocationTargetException e) {
logger.error("Erro ao transformar em CSV", e);
}
}
out.write('\n');
}
}
private List<String> getObjectGetters(TsvResponse response) {
List<String> getters = new ArrayList<>();
for (Method method : ReflectionUtils.getAllDeclaredMethods(response.getRecords().get(0).getClass())) {
String methodName = method.getName();
if (methodName.startsWith("get") && !methodName.equals("getClass")) {
getters.add(methodName);
}
}
sort(getters);
return getters;
}
private void writeColumnTitles(TsvResponse response, OutputStream out) throws IOException {
for (String columnTitle : response.getColumnTitles()) {
out.write(columnTitle.getBytes());
out.write('\t');
}
out.write('\n');
}
}
TsvResponse.java
public class TsvResponse {
private final String filename;
private final List records;
private final String[] columnTitles;
public TsvResponse(List records, String filename, String ... columnTitles) {
this.records = records;
this.filename = filename;
this.columnTitles = columnTitles;
}
public String getFilename() {
return filename;
}
public List getRecords() {
return records;
}
public String[] getColumnTitles() {
return columnTitles;
}
}
And on SpringContext.xml add the following:
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="com.mypackage.TsvMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
So, you can use on your controller like this:
#RequestMapping(value="/tsv", method= RequestMethod.GET, produces = "text/tsv")
#ResponseBody
public TsvResponse tsv() {
return new TsvResponse(myListOfPojos, "fileName.tsv",
"Name", "Email", "Phone", "Mobile");
}