Mockito UnfinishedVerificationException - java

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));

Related

How to write JUnit for this controller?

private static final Logger LOGGER = LoggerFactory.getLogger(InfoController.class);
#RequestMapping(value = "/version", method = {RequestMethod.GET, RequestMethod.POST})
#ResponseBody
public Map<String, String> getVersion() throws IOException {
final String versionKey = "Version";
return Collections.singletonMap(versionKey, loadManifest().getProperty(versionKey));
}
#RequestMapping(value = "/info", method = {RequestMethod.GET, RequestMethod.POST})
#ResponseBody
#SuppressWarnings("unchecked cast")
public Map<String, String> getInfo() throws IOException {
return Collections.checkedMap((Map) loadManifest(), String.class, String.class);
}
private Properties loadManifest() throws IOException {
final InputStream stream = this.getClass().getResourceAsStream("/META-INF/MANIFEST.MF");
try {
final Properties manifest = new Properties();
manifest.load(stream);
return manifest;
} finally {
if (stream != null) {
try {
stream.close();
} catch (IOException e){
LOGGER.error(e.getMessage(),e);
}
}
}
}
}
I am new to the JUnit and don't know how to cover the controllers. It would be great if get an example for this so that I can understand how to write for other controllers
MockMvc is hopefully what you're after
https://spring.io/guides/gs/testing-web/

How can i test Solr SearchComponent - JUnit Tests

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!

Port Lucene 3.6.2 Analyzer to Lucene 5.5.0

For Lucene 3.6.2 I have a following Analyzer:
public final class StandardAnalyzerV36 extends Analyzer {
private Analyzer analyzer;
public StandardAnalyzerV36() {
analyzer = new StandardAnalyzer(Version.LUCENE_36);
}
public StandardAnalyzerV36(Set<?> stopWords) {
analyzer = new StandardAnalyzer(Version.LUCENE_36, stopWords);
}
#Override
public final TokenStream tokenStream(String fieldName, Reader reader) {
return analyzer.tokenStream(fieldName, new HTMLStripCharFilter(CharReader.get(reader)));
}
#Override
public final TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException {
return analyzer.reusableTokenStream(fieldName, reader);
}
}
Could you please help me to port it on Analyzer for Lucene 5.5.0 ? The Analyzer interface was changed in the new version.
UPDATED
I have reimplemented this Analyzer to following:
public final class StandardAnalyzerV36 extends Analyzer {
public static final CharArraySet STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET;
#Override
protected TokenStreamComponents createComponents(String fieldName) {
final ClassicTokenizer src = new ClassicTokenizer();
TokenStream tok = new StandardFilter(src);
tok = new StopFilter(new LowerCaseFilter(tok), STOP_WORDS_SET);
return new TokenStreamComponents(src, tok);
}
#Override
protected Reader initReader(String fieldName, Reader reader) {
return new HTMLStripCharFilter(reader);
}
but my tests fails on following call:
tokens = LuceneUtils.tokenizeString(analyzer, "[{(RDBMS)}]");
public static List<String> tokenizeString(Analyzer analyzer, String string) {
List<String> result = new ArrayList<String>();
try {
TokenStream stream = analyzer.tokenStream(null, new StringReader(string));
stream.reset();
while (stream.incrementToken()) {
result.add(stream.getAttribute(CharTermAttribute.class).toString());
}
} catch (IOException e) {
// not thrown b/c we're using a string reader...
throw new RuntimeException(e);
}
return result;
}
with a following exception:
java.lang.IllegalStateException: TokenStream contract violation: close() call missing
at org.apache.lucene.analysis.Tokenizer.setReader(Tokenizer.java:90)
at org.apache.lucene.analysis.Analyzer$TokenStreamComponents.setReader(Analyzer.java:315)
at org.apache.lucene.analysis.Analyzer.tokenStream(Analyzer.java:143)
What is wrong with this code ?
Finally I got it working:
public final class StandardAnalyzerV36 extends Analyzer {
public static final CharArraySet STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET;
#Override
protected TokenStreamComponents createComponents(String fieldName) {
final ClassicTokenizer src = new ClassicTokenizer();
TokenStream tok = new StandardFilter(src);
tok = new StopFilter(new LowerCaseFilter(tok), STOP_WORDS_SET);
return new TokenStreamComponents(src, tok);
}
#Override
protected Reader initReader(String fieldName, Reader reader) {
return new HTMLStripCharFilter(reader);
}
}
public class LuceneUtils {
public static List<String> tokenizeString(Analyzer analyzer, String string) {
List<String> result = new ArrayList<String>();
TokenStream stream = null;
try {
stream = analyzer.tokenStream(null, new StringReader(string));
stream.reset();
while (stream.incrementToken()) {
result.add(stream.getAttribute(CharTermAttribute.class).toString());
}
} catch (IOException e) {
// not thrown b/c we're using a string reader...
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(stream);
}
return result;
}
}

How to make Spring Controller to return CSV from a POJO? [duplicate]

This question already has answers here:
Configuring Spring MVC controller to send file to client
(2 answers)
Closed 8 years ago.
Given a simple Java Object:
public class Pojo {
private String x;
private String y;
private String z;
//... getters/setters ...
}
Is there some lib that i can put on my project that will make a controller like this:
#RequestMapping(value="/csv", method=RequestMethod.GET, produces= MediaType.TEXT_PLAIN)
#ResponseBody
public List<Pojo> csv() {
//Some code to get a list of Pojo objects
//...
return myListOfPojos;
}
To produce a csv file of my Pojos? For a Json result, i use Jackson lib. I need another lib for CSV results.
As a simple variant. You can generate csv by any way you want and return it as String.
Something like this:
#RequestMapping(value="/csv", method=RequestMethod.GET)
#ResponseBody
public String csv() {
//Some code to get a list of Pojo objects
//...
StringBuilder sb = new StringBuilder();
for (Pojo pojo: myListOfPojos){
sb.append(pojo.getX());
sb.append(",");
sb.append(pojo.getY());
sb.append(",");
sb.append(pojo.getZ());
sb.append("\n");
}
return sb.toString;
}
Should work.
Autogenerate this strings by reflection looks like simple work too.
Based on another question, i did my own HTTPMessageConverter for Tsv Responses.
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");
}

Configuring Spring MVC controller to send file to client

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");
}

Categories