spring bean is null in mockito test - java

I'm using spring 5 and mockito, but in a test process i have a problem where my bean is done null and i get a NullPointerException, how can i fix it?
infact, my SpringContext.getBean returns null but it work correctly when the application is in runtime mode.
java.lang.NullPointerException
at com.novinkish.batch.ParallerMakerTest.testSendData(ParallerMakerTest.java:53)
.
.
Caused by: java.lang.NullPointerException
at com.novinkish.batch.util.SpringContext.getBean(SpringContext.java:14)
my test class is like this:
#RunWith(MockitoJUnitRunner.class)
public class ParallerMakerTest {
#Mock
private CommonRestCallerImpl restCallerImpl;
#Test
public void testSendData(){
PersonDTO personDTO_1 = new PersonDTO("1111111111", "name_1", "L_name_1", "2000/05/09", (short) 0);
PersonDTO personDTO_2 = new PersonDTO(4646L, "1111111111", "name_1", "L_name_1", "2000/05/09", (short) 1);
List<PersonDTO> resultDtoList = new ArrayList<PersonDTO>();
try {
when(restCallerImpl.callService(ServiceNameJNDI.SAVE_PERSON, personDTO_1, PersonDTO.class)).thenReturn(personDTO_2);
} catch (Exception e) {
e.printStackTrace();
}
ForkJoinPool pool = new ForkJoinPool();
PersonSessionParallerMaker maker = new PersonSessionParallerMaker(restCallerImpl, Arrays.asList(personDTO_1));
pool.execute(maker);
try {
pool.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
resultDtoList = (List<PersonDTO>) pool.invoke(maker);
Assert.assertNotNull(resultDtoList);
Assert.assertEquals(1, ((PersonDTO)resultDtoList.get(0)).getStatus().intValue());
}
and my class is:
public class PersonSessionParallerMaker extends RecursiveTask {
private CommonRestCaller restCaller;
private List<PersonDTO> initList = new ArrayList<PersonDTO>();
private List<PersonDTO> resultList = new ArrayList<PersonDTO>();
private PersonDTO target;
public PersonSessionParallerMaker(CommonRestCaller restCaller, List<PersonDTO> initList) {
this.initList = initList;
this.restCaller = restCaller;
}
public PersonSessionParallerMaker(PersonDTO target) {
this.target = target;
}
#Override
protected Object compute() {
/*MASTER Thread*/
if (target == null) {
for (PersonDTO personDTO : initList) {
/*CREATE FORK (SUB THREAD)*/
PersonSessionParallerMaker parallerMaker = new PersonSessionParallerMaker(personDTO);
invokeAll(parallerMaker);
resultList.add((PersonDTO) parallerMaker.join());
}
return resultList;
} else if (target.getStatus() == 0) {
callService();
return target;
} else
return null;
}
public void callService() {
System.out.println("1.restCaller = " + restCaller);
/*For Unit Test*/
if (restCaller == null) {
System.out.println("2.restCaller = " + restCaller);
restCaller = (CommonRestCaller) SpringContext.getBean(CommonRestCallerImpl.class);
System.out.println("3.restCaller = " + restCaller);
}
try {
System.out.println("target.toString() = " + target.toString());
target = (PersonDTO) restCaller.callService(ServiceNameJNDI.SAVE_PERSON, target, PersonDTO.class);
} catch (Exception e) {
e.printStackTrace();
target.setStatus((short) 2);
}
}
}

You are mixing up unit testing and integration testing here.
What you have written, is a unit test. Unit tests run - per definiton - isolated from the whole application, therefore you have no access to the application context. The purpose of a unit test is to test one specific class.
If you want to test the behaviour of your whole application, you have to write an integration test.
See https://www.baeldung.com/spring-boot-testing#integration-testing-with-springboottest for further reading.

Related

Custom hashCode implementation for ConcurrentSkipListMap doen't work as expected

The idea is to allow ConcurrentSkipListMap to store only one ApprovalRequest which has unique customerId and its state is PENDING. I supplied overridden hashCode and equals implementations. Moreover, in unit test the ApprovalRequest suppose to create a new instance using lombok's #Builder. How to make it work?
#Component
public class LoanRepository {
private final ConcurrentSkipListMap<ApprovalRequest, ConcurrentHashMap<String, Decision>> pendingStorage;
public synchronized void saveAsPending(final LoanApprovalRequest loanApprovalRequest) {
log.info("Trying to save: {}", loanApprovalRequest);
if (pendingStorage.containsKey(loanApprovalRequest)) {
log.error("Attempt to save duplicate pending LoanApprovalRequest: {}", loanApprovalRequest);
throw new BusinessRuleException("Attempt to save duplicate pending LoanApprovalRequest: " + loanApprovalRequest);
}
ConcurrentHashMap<String, Decision> decisions = new ConcurrentHashMap<>();
for (Approver approver : loanApprovalRequest.getApprovers()) {
Decision pendingDecision = Decision.builder()
.customerId(loanApprovalRequest.getCustomerId())
.approverUsername(approver.getName())
.state(PENDING)
.build();
decisions.put(approver.getName(), pendingDecision);
}
if (pendingStorage.putIfAbsent(loanApprovalRequest, decisions) == null) {
log.info("Successfully added new LoanApprovalRequest: {}", loanApprovalRequest);
} else {
log.error("Save failed. Duplicate LoanApprovalRequest: {}", loanApprovalRequest);
throw new BusinessRuleException("Fail to add LoanApprovalRequest. Duplicate LoanApprovalRequest: " + loanApprovalRequest);
}
log.info("New storage size: {}", pendingStorage.size());
}
}
Test:
ConcurrentSkipListMap<ApprovalRequest, ConcurrentHashMap<String, Decision>> pendingStorage;
#BeforeEach
public void each() {
mainStorage = new ConcurrentSkipListMap<>();
pendingStorage = new ConcurrentSkipListMap<>();
repository = new LoanRepository(mainStorage, pendingStorage, threadPoolTaskScheduler);
}
#Order(2)
#Test
public void givenTwoProducers_whenSaving30LoanApprovalRequestsConcurrently_expectCorrectStatistics() throws InterruptedException {
final int numberOfThreads = 2;
final ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);
CountDownLatch completedThreadCounter = new CountDownLatch(numberOfThreads);
CountDownLatch readyThreadCounter = new CountDownLatch(numberOfThreads);
CountDownLatch callingThreadBlocker = new CountDownLatch(1);
Runnable producer1 = () -> {
try {
readyThreadCounter.countDown();
callingThreadBlocker.await();
Set<Approver> approver = new HashSet<>();
approver.add(new Approver("Under €1_000 Approver"));
LoanApprovalRequest request;
for (int i = 0; i < 5; i++) {
request = LoanApprovalRequest.builder()
.customerId("1X-XXXX-XAX")
.decisionState(PENDING)
.loanAmount(BigDecimal.valueOf(123.01 + i))
.approvers(approver)
.timestamp(ZonedDateTime.now())
.build();
try {
repository.saveAsPending(request);
} catch (BusinessRuleException be) {
System.out.println(be.getMessage());
}
Thread.sleep(i * 10L);
}
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
} finally {
completedThreadCounter.countDown();
}
};
Runnable producer2 = () -> {
try {
readyThreadCounter.countDown();
callingThreadBlocker.await();
Set<Approver> approver = new HashSet<>();
approver.add(new Approver("Under €9_000 Approver"));
LoanApprovalRequest request;
for (int i = 0; i < 5; i++) {
request = LoanApprovalRequest.builder()
.customerId("2X-XXXX-XWX")
.loanAmount(BigDecimal.valueOf(1023.55 + i * 10))
.decisionState(PENDING)
.approvers(approver)
.timestamp(ZonedDateTime.now())
.build();
try {
repository.saveAsPending(request);
} catch (BusinessRuleException be) {
System.out.println(be.getMessage());
}
Thread.sleep(i * 10L);
}
completedThreadCounter.countDown();
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
} finally {
completedThreadCounter.countDown();
}
};
executorService.execute(producer1);
executorService.execute(producer2);
readyThreadCounter.await();
callingThreadBlocker.countDown();
completedThreadCounter.await();
executorService.shutdown();
Statistics statistics = repository.getStatistics(Duration.ofSeconds(60));
assertEquals(2, statistics.getCount());
}
LoanApprovalRequest
#Builder
#Data
#NoArgsConstructor
#AllArgsConstructor
public class LoanApprovalRequest implements ApprovalRequest, Comparable<LoanApprovalRequest> {
public LoanApprovalRequest(ZonedDateTime zonedDateTime) {
this.timestamp = zonedDateTime;
}
String customerId;
BigDecimal loanAmount;
Set<Approver> approvers;
ZonedDateTime timestamp;
DecisionState decisionState;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LoanApprovalRequest that = (LoanApprovalRequest) o;
return customerId.equals(that.customerId);
}
#Override
public int hashCode() {
return customerId.hashCode();
}
#Override
public int compareTo(LoanApprovalRequest o) {
return this.timestamp.compareTo(o.timestamp);
}
#Override
public String toString() {
return "LoanApprovalRequest{" +
"customerId='" + customerId + '\'' +
", loanAmount=" + loanAmount +
// ", approvers=[" + approvers.stream().map(Approver::getName).collect(Collectors.joining(",")) + "]" +
// ", timestamp=" + timestamp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:nnnnnnnnn").withZone(ZoneId.of("UTC"))) +
", decisionState=" + decisionState +
'}';
}
}
ConcurrentSkipListMap is not based on hash codes, but on ordering/comparisons.
So you will have to use that customerId in compareTo as well (or supply the Map with a different Comparator based on customerId). Otherwise it will not be consistent with equals and the Map key uniqueness checks won't work.

Methods in interface not getting covered in mockito junit

I am using mockito-junit to test a piece of my code. As progressing I found out that there was an interface implemented in the main file which I was testing, when the test was running I found that the line where interface method is called get's covered but the real method doesn't get's covered.
This the code for the main file:
public class ExtractCurrencyDataTask {
private static final Logger LOGGER = LoggerFactory.getLogger(ExtractCurrencyDataTask.class);
#Autowired
private ExtractCurrencyService extractCurrencyService;
public void writeCurrencyListToFile(List<Currency> currencyList) {
if (currencyList != null && !currencyList.isEmpty()) {
String dir = "A path";
String fileName = "A filename";
String writeToFile = dir + "/" + fileName + ".writing";
String renameFile = dir + "/" + fileName + ".dat";
BufferedWriter writer = null;
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(writeToFile);
writer = new BufferedWriter(fileWriter);
extractCurrencyService.extractCurrencyList(currencyList, writer);
} catch (Exception e) {
throw new RuntimeException("Error writing Currency codes", e);
} finally {
if (writer != null) {
try {
writer.close();
fileWriter.close();
} catch (IOException e) {
LOGGER.info("Exception occured while closing the file writer", e);
}
moveFile(writeToFile, renameFile);
}
}
}
}
private void moveFile(String writeToFile, String renameFile) {
try {
FileUtils.moveFile(FileUtils.getFile(writeToFile), FileUtils.getFile(renameFile));
} catch (IOException e) {
LOGGER.info("Exception occured while moving file from writing to dat", e);
}
}
Here extractCurrencyService is the interface which I have mentioned.
The interface:
public interface ExtractCurrencyService {
public void extractCurrencyList(List<Currency> currency, Writer writer);
}
This the method definition which is done another file which implements same interface Filename:ExtractCurrencyServiceImpl.java
public class ExtractCurrencyServiceImpl implements ExtractCurrencyService {
private static final String SEP = "|";
private static final String NEWLINE = "\n";
#Override
public void extractCurrencyList(List<Currency> currencyList, Writer writer) {
if (currencyList != null) {
currencyList.forEach(currency -> {
String code = currency.getCode();
String name = currency.getName() == null ? "" : currency.getName();
Long noOfDecimals = currency.getNumberOfDecimals();
RoundingMethodValue roundingMethod = currency.getRoundingMethod();
boolean isDealCurrency = currency.isDealCurrency();
String description = currency.getDescription() == null ? "" : currency.getDescription();
try {
writer.write(createCurrencyDataLine(code,
name,
noOfDecimals,
roundingMethod,
isDealCurrency,
description));
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
}
private String createCurrencyDataLine(String code,
String name,
Long noOfDecimals,
RoundingMethodValue roundingMethod,
boolean isdealCurrency,
String description) {
return code + SEP + name + SEP + noOfDecimals.toString() + SEP + roundingMethod.toString() + SEP
+ isdealCurrency + SEP + description + NEWLINE;
}
public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
Map<Object, Boolean> map = new ConcurrentHashMap<>();
return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}
This is the test file:
#RunWith(MockitoJUnitRunner.class)
public class ExtractCurrencyDataTaskTest {
#Mock
private Currency mockCurrency;
#Mock
private ExtractCurrencyService mockExtractCurrencyService;
#Mock
private BufferedWriter mockBufferWriter;
#Mock
private Bean mockBean;
#InjectMocks
private ExtractCurrencyDataTask extractCurrencyDataTask;
#Test
public void writeCurrencyListToFileTest() {
List<Currency> currencyList = new ArrayList();
when(mockCurrency.getCode()).thenReturn("USD");
when(mockCurrency.getNumberOfDecimals()).thenReturn((long) 2);
when(mockCurrency.getRoundingMethod()).thenReturn(enum value);
when(mockCurrency.isDealCurrency()).thenReturn(true);
when(mockCurrency.getName()).thenReturn("US Dollars");
when(mockCurrency.getDescription()).thenReturn("Currency Description");
currencyList.add(mockCurrency);
extractCurrencyDataTask.writeCurrencyListToFile(currencyList);
}
}
This the configuration for Autowired bean
#Bean
public ExtractCurrencyService extractCurrencyService() {
return new ExtractCurrencyServiceImpl();
}
As you can see the real output of this process is a file will be created in a path mentioned with some data. Here in this test I am mocking the data and passing it to main file. Main file is the created file in respective path but there is no data in the file.
The data writing part is done by the interface method. This is the part where I need help.
Thanks in advance....
You are injecting a mock of ExtractCurrencyService into your tested class. So the test is running with this mock instance instead of ExtractCurrencyServiceImpl. The current behaviour is that your ExtractCurrencyDataTasktested class is calling to extractCurrencyService#extractCurrencyList, but this extractCurrencyService is a mock, not your real implementation, so the call is done but it does nothing.
If you want to unit test ExtractCurrencyDataTask then thats ok, but maybe you should assert the call to extractCurrencyService#extractCurrencyList is done in the way you expect.
If you want to unit test ExtractCurrencyServiceImpl then create a unit test for this class.
If you want to test the interaction between these two classes then create an integration test where ExtractCurrencyDataTask has injected a real instance of ExtractCurrencyServiceImpl, not a mock.

jASEN in Java project to detect spam email

I want to use jASEN in my Java project, in order to retrieve the spam score for a set of emails I have.
My code is as follows:
public static double Get_jASEN_Score(MimeMessage mm) {
double jASEN_score = -1;
try {
// Initialise the scanner
JasenScanner.getInstance().init();
JasenScanResult result = JasenScanner.getInstance().scan(mm);
jASEN_score = result.getProbability();
} catch (JasenException e) {
Console.Console.Print_To_Console(String.format("jASEN Spam filter Error: %s", e.getMessage()), true, false);
}
return jASEN_score;
}
The problem is that the: JasenScanner.getInstance().init(); line process time is everlasting. I placed the "jasen-conf" folder at the right place.
Any suggest what is the problem?
try this:
private static final JasenScanner JASEN_SCANNER = JasenConnection.getInstance();
public static double getJASENScore(MimeMessage message) {
try {
JasenScanResult result = JASEN_SCANNER.scan(message);
return result.getProbability();
} catch (JasenException ex) {
LOGGER.info("JASON error; " + ex.getMessage());
}
return -1;
}
edit:
public class JasenConnection {
private static JasenScanner jasenScanner;
protected JasenConnection() {
try {
JasenScanner.getInstance().init();
ErrorHandlerBroker.getInstance().setErrorHandler(new EmptyErrorHandler());
jasenScanner = JasenScanner.getInstance();
} catch (JasenException ex) {
//LOGGER.info(ex.getMessage());
}
}
public static JasenScanner getInstance() {
if (null == jasenScanner) {
new JasenConnection();
}
return jasenScanner;
}
}

Looking for advice on how to optimize runtime of specific code

This is my first posting here, hope I won't seem too desperate with my question.
I have a work task which involves comparing two large set of names to see if matching exists between them (regardless of order of words in the names).
I've tried both a regular, more straightforward approach and also one using Regex.
Standard approach:
public static boolean isMatch(String terroristName, String clientName) {
String[] terroristArray = terroristName.split(" ");
String[] clientArray = clientName.split(" ");
int size = clientArray.length;
int ctrl = 0;
boolean alreadyFound = false;
for (String client : clientArray) {
for (String terrorist : terroristArray) {
//if already found a match, stop comparing with rest of the words from terrorist name
if (!alreadyFound)
if (client.compareTo(terrorist) == 0) {
alreadyFound = true;
ctrl++;
break;
}
}
alreadyFound = false;
if (ctrl == 0 && !alreadyFound) {
//if first word of client is not found in whole terrorist name
//then exit loop, no match possible
break;
}
}
if (ctrl == size)
return true;
else
return false;
}
Regex approach:
public static boolean isRegexMatch(String terroristName, String clientName) {
boolean result = false;
String[] clientNameArray = clientName.split(" ");
String myPattern = "^";
//build pattern using client name
for (String cname : clientNameArray) {
myPattern += "(?=.*\\b" + cname + "\\b)";
}
myPattern += ".*$";
Pattern pattern = Pattern.compile(myPattern);
Matcher matcher = pattern.matcher(terroristName);
// check all occurance
while (matcher.find()) {
result = true;
}
return result;
}
Loop comparing the 2 lists of names:
for (Person terrorist : terrorists) {
System.setOut(matchPrintStream);
for (Person client : clients) {
if (Util.isRegexMatch(terrorist.getNoDuplicatesName(), client.getName())) {
System.out.println(client.getId() + ";" + client.getName() + ";" + terrorist.getId() + ";" +
terrorist.getName());
}
}
}
The two sets have the following sizes:
terrorist = aprox 16000
clients = aprox 3.4 million
Runtime of both methods is quite slow:
ps -ef | grep 42810
42810 41919 99 17:47 pts/0 00:52:23 java -Xms1024M -Xmx1024M -classpath ojdbc6.jar:TerroristBuster.jar ro.btrl.mis.mihai.Main
By the time above of 00:52:23 runtime, it had processed about 170 entries, meaning it would need several days to complete. I know it has a large complexity, unsure how to lower it. What do you think of maybe using something other than List? I figured it would the most fast using foreach since of the random access.
Can this code be improved/changed in any way to improve the runtime, or am i just dealing with a too large set of data?
If you can use Java 8 this should be very easy to parallelise.
First, you don't have that many clients, so preprocess those:
final Collection<Collection<String>> processedClients = clients.parallelStream().
map(c -> c.split("\\s+")).
map(Arrays::asList).
collect(toList());
This takes each client name, splits it into the parts, and then uses the asList wrapper to turn it into a List. This is done parallelised, so should be fast.
Next we need to loop over all the terrorists:
terrorists.parallelStream().
map(t -> t.split("\\s+")).
map(t -> Stream.of(t).collect(toSet())).
forEach(t -> {
processedClients.parallelStream().forEach(c -> {
if (t.containsAll(c)) {
System.out.println("Match found t:" + t + ", c:" + c);
}
});
});
Here, for each terrorist, we split their name, but this time we turn it into a Set because Set has O(1) contains() - this means checking whether a whole client name is contained in a whole terrorist name will only take time proportional to the size of the client name.
We then use forEach to loop over the terrorists and another forEach to loop over the clients, we check is the terrorists name Set containsAll the client name.
Again this is in parallel.
In theory it shouldn't take long at all. Storing the processed client names in memory might require a bit of RAM, but it shouldn't be too much - about 1GB.
EDIT
Here is a rewrite to an earlier version (1.7, but if you remove the diamond notation it should work on 1.5)
First you need two processing classes, these are submitted to individual work threads:
final class NameProcessor implements Callable<Collection<String>> {
private final String name;
public NameProcessor(final String name) {
this.name = name;
}
#Override
public Collection<String> call() throws Exception {
return Arrays.asList(name.split("\\s+"));
}
}
final class TerroristProcessor implements Runnable {
private final String name;
public TerroristProcessor(final String name) {
this.name = name;
}
#Override
public void run() {
final Set<String> splitName = new HashSet<>(Arrays.asList(name.split("\\s+")));
for (final Collection<String> client : proccessedClients) {
if (splitName.containsAll(client)) {
System.out.println("Match found t:" + name + ", c:" + client);
}
}
}
}
Now you need to ExecutorService and an ExecutorCompletionService:
final ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
final ExecutorCompletionService<Collection<String>> cs = new ExecutorCompletionService<>(es);
Now you first need to process your clients, as before:
for (final String name : clients) {
cs.submit(new NameProcessor(name));
}
final Collection<Collection<String>> proccessedClients = new LinkedList<>();
for (int i = 0; i < clients.size(); ++i) {
try {
proccessedClients.add(cs.take().get());
} catch (InterruptedException ex) {
return;
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
And then process the terrorists:
final Collection<Future<?>> futures = new LinkedList<>();
for (final String terrorist : terrorists) {
futures.add(es.submit(new TerroristProcessor(terrorist)));
}
es.shutdown();
es.awaitTermination(1, TimeUnit.DAYS);
for (final Future<?> f : futures) {
try {
f.get();
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
The loop over the futures is to check for processing errors.
EDIT
The OP wants to process custom objects rather than collections of String.
I would assume you have some sort of Person class like so:
final class Person {
private final int id;
private final String name;
//constructor
//getters and setters
}
Then you can simply create a wrapper class like so:
final class PersonWrapper {
private final Person person;
private final Collection<String> processedName;
//constructor
//getters and setters
}
And create a result class like so:
final class ProblemClient {
private final Person client;
private final Person terrorist;
//constructor
//getters and setters
}
And simply rewrite the code appropriately:
final class NameProcessor implements Callable<PersonWrapper> {
private final Person person;
public NameProcessor(final Person person) {
this.person = person;
}
#Override
public PersonWrapper call() throws Exception {
return new PersonWrapper(person, Arrays.asList(person.getName().split("\\s+")));
}
}
final ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
final ExecutorCompletionService<PersonWrapper> cs = new ExecutorCompletionService<>(es);
for (final Person client : clients) {
cs.submit(new NameProcessor(client));
}
final Collection<PersonWrapper> proccessedClients = new LinkedList<>();
for (int i = 0; i < clients.size(); ++i) {
try {
proccessedClients.add(cs.take().get());
} catch (InterruptedException ex) {
return;
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
final class TerroristProcessor implements Runnable {
private final Person person;
private final Collection<ProblemClient> results;
public TerroristProcessor(final Person person, final Collection<ProblemClient> results) {
this.person = person;
this.results = results;
}
#Override
public void run() {
final Set<String> splitName = new HashSet<>(Arrays.asList(person.getName().split("\\s+")));
for (final PersonWrapper client : proccessedClients) {
if (splitName.containsAll(client.getProcessedName())) {
results.add(new ProblemClient(client.getPerson(), person));
}
}
}
}
final Collection<ProblemClient> results = new ConcurrentLinkedQueue<>();
final Collection<Future<?>> futures = new LinkedList<>();
for (final Person terrorist : terrorists) {
futures.add(es.submit(new TerroristProcessor(terrorist, results)));
}
es.shutdown();
es.awaitTermination(1, TimeUnit.DAYS);
for (final Future<?> f : futures) {
try {
f.get();
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
//process results
for (final ProblemClient problemClient : results) {
//whatever.
}
As I said, it might be informative to see what the outcome of preprocessing terrorists first and then looping over clients is too:
final class TerroristPreprocessor implements Callable<PersonWrapper> {
private final Person person;
public TerroristPreprocessor(final Person person) {
this.person = person;
}
#Override
public PersonWrapper call() throws Exception {
final Set<String> splitName = new HashSet<>(Arrays.asList(person.getName().split("\\s+")));
return new PersonWrapper(person, splitName);
}
}
final ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
final ExecutorCompletionService<PersonWrapper> cs = new ExecutorCompletionService<>(es);
for (final Person terrorist : terrorists) {
cs.submit(new TerroristPreprocessor(terrorist));
}
final Collection<PersonWrapper> proccessedTerrorists = new LinkedList<>();
for (int i = 0; i < terrorists.size(); ++i) {
try {
proccessedTerrorists.add(cs.take().get());
} catch (InterruptedException ex) {
return;
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
final class ProblemClientFinder implements Runnable {
private final Person client;
private final Collection<ProblemClient> results;
public ProblemClientFinder(final Person client, final Collection<ProblemClient> results) {
this.client = client;
this.results = results;
}
#Override
public void run() {
final Collection<String> splitName = Arrays.asList(client.getName().split("\\s+"));
for (final PersonWrapper terrorist : proccessedTerrorists) {
if (terrorist.getProcessedName().containsAll(splitName)) {
results.add(new ProblemClient(client, terrorist.getPerson()));
}
}
}
}
final Collection<ProblemClient> results = new ConcurrentLinkedQueue<>();
final Collection<Future<?>> futures = new LinkedList<>();
for (final Person client : clients) {
futures.add(es.submit(new ProblemClientFinder(client, results)));
}
es.shutdown();
es.awaitTermination(1, TimeUnit.DAYS);
for (final Future<?> f : futures) {
try {
f.get();
} catch (ExecutionException ex) {
throw new RuntimeException(ex);
}
}
//process results
for (final ProblemClient problemClient : results) {
//whatever.
}

easymock expect not working and still calling actual method

I want to test MessageProcessor1.listAllKeyword method, which in turn
calls HbaseUtil1.getAllKeyword method. Initialy, I had to deal with a problem associated with the static initializer and the constructor. The problem was to initialize a HBASE DB connection. I used powerMock to suppress static and constructor calls and it worked fine.
Even though I mocked HbaseUtil1.getAllKeyword method, actual method is being called and executes all HBase code leading to an exception, in which HBASE server is not up.
EasyMock.expect(hbaseUtil.getAllKeyword("msg", "u1")).andReturn(expectedList);
Please give me any idea on how to avoid an actual method call. I tried many ways but none of them worked.
public class MessageProcessor1
{
private static Logger logger = Logger.getLogger("MQ-Processor");
private final static String CLASS_NAME = "MessageProcessor";
private static boolean keywordsTableExists = false;
public static PropertiesLoader props;
HbaseUtil1 hbaseUtil;
/**
* For checking if table exists in HBase. If doesn't exists, will create a
* new table. This runs only once when class is loaded.
*/
static {
props = new PropertiesLoader();
String[] userTablefamilys = {
props.getProperty(Constants.COLUMN_FAMILY_NAME_COMMON_KEYWORDS),
props.getProperty(Constants.COLUMN_FAMILY_NAME_USER_KEYWORDS) };
keywordsTableExists = new HbaseUtil()
.creatTable(props.getProperty(Constants.HBASE_TABLE_NAME),
userTablefamilys);
}
/**
* This will load new configuration every time this class instantiated.
*/
{
props = new PropertiesLoader();
}
public String listAllKeyword(String userId) throws IOException {
HbaseUtil1 util = new HbaseUtil1();
Map<String, List<String>> projKeyMap = new HashMap<String, List<String>>();
//logger.info(CLASS_NAME+": inside listAllKeyword method");
//logger.debug("passed id : "+userId);
List<String> qualifiers = util.getAllKeyword("msg", userId);
List<String> keywords = null;
for (String qualifier : qualifiers) {
String[] token = qualifier.split(":");
if (projKeyMap.containsKey(token[0])) {
projKeyMap.get(token[0]).add(token[1]);
} else {
keywords = new ArrayList<String>();
keywords.add(token[1]);
projKeyMap.put(token[0], keywords);
}
}
List<Project> projects = buildProject(projKeyMap);
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation()
.create();
System.out.println("Json projects:::" + gson.toJson(projects));
//logger.debug("list all keyword based on project::::"+ gson.toJson(projects));
//return gson.toJson(projects);
return "raj";
}
private List<Project> buildProject(Map<String, List<String>> projKeyMap) {
List<Project> projects = new ArrayList<Project>();
Project proj = null;
Set<String> keySet = projKeyMap.keySet();
for (String hKey : keySet) {
proj = new Project(hKey, projKeyMap.get(hKey));
projects.add(proj);
}
return projects;
}
//#Autowired
//#Qualifier("hbaseUtil1")
public void setHbaseUtil(HbaseUtil1 hbaseUtil) {
this.hbaseUtil = hbaseUtil;
}
}
public class HbaseUtil1 {
private static Logger logger = Logger.getLogger("MQ-Processor");
private final static String CLASS_NAME = "HbaseUtil";
private static Configuration conf = null;
public HbaseUtil1() {
PropertiesLoader props = new PropertiesLoader();
conf = HBaseConfiguration.create();
conf.set(HConstants.ZOOKEEPER_QUORUM, props
.getProperty(Constants.HBASE_CONFIGURATION_ZOOKEEPER_QUORUM));
conf.set(
HConstants.ZOOKEEPER_CLIENT_PORT,
props.getProperty(Constants.HBASE_CONFIGURATION_ZOOKEEPER_CLIENT_PORT));
conf.set("hbase.zookeeper.quorum", props
.getProperty(Constants.HBASE_CONFIGURATION_ZOOKEEPER_QUORUM));
conf.set(
"hbase.zookeeper.property.clientPort",
props.getProperty(Constants.HBASE_CONFIGURATION_ZOOKEEPER_CLIENT_PORT));
}
public List<String> getAllKeyword(String tableName, String rowKey)
throws IOException {
List<String> qualifiers = new ArrayList<String>();
HTable table = new HTable(conf, tableName);
Get get = new Get(rowKey.getBytes());
Result rs = table.get(get);
for (KeyValue kv : rs.raw()) {
System.out.println("KV: " + kv + ", keyword: "
+ Bytes.toString(kv.getRow()) + ", quaifier: "
+ Bytes.toString(kv.getQualifier()) + ", family: "
+ Bytes.toString(kv.getFamily()) + ", value: "
+ Bytes.toString(kv.getValue()));
qualifiers.add(new String(kv.getQualifier()));
}
table.close();
return qualifiers;
}
/**
* Create a table
*
* #param tableName
* name of table to be created.
* #param familys
* Array of the name of column families to be created with table
* #throws IOException
*/
public boolean creatTable(String tableName, String[] familys) {
HBaseAdmin admin = null;
boolean tableCreated = false;
try {
admin = new HBaseAdmin(conf);
if (!admin.tableExists(tableName)) {
HTableDescriptor tableDesc = new HTableDescriptor(tableName);
for (int i = 0; i < familys.length; i++) {
tableDesc.addFamily(new HColumnDescriptor(familys[i]));
}
admin.createTable(tableDesc);
System.out.println("create table " + tableName + " ok.");
}
tableCreated = true;
admin.close();
} catch (MasterNotRunningException e1) {
e1.printStackTrace();
} catch (ZooKeeperConnectionException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return tableCreated;
}
}
Below is my Test class.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MessageProcessor1.class)
#SuppressStaticInitializationFor("com.serendio.msg.mqProcessor.MessageProcessor1")
public class MessageProcessorTest1 {
private MessageProcessor1 messageProcessor;
private HbaseUtil1 hbaseUtil;
#Before
public void setUp() {
messageProcessor = new MessageProcessor1();
hbaseUtil = EasyMock.createMock(HbaseUtil1.class);
}
#Test
public void testListAllKeyword(){
List<String> expectedList = new ArrayList<String>();
expectedList.add("raj:abc");
suppress(constructor(HbaseUtil1.class));
//suppress(method(HbaseUtil1.class, "getAllKeyword"));
try {
EasyMock.expect(hbaseUtil.getAllKeyword("msg", "u1")).andReturn(expectedList);
EasyMock.replay();
assertEquals("raj", messageProcessor.listAllKeyword("u1"));
} catch (IOException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
}
The HbaseUtil1 is instantiated within the listAllKeyword method
public String listAllKeyword(String userId) throws IOException {
HbaseUtil1 util = new HbaseUtil1();
...
So the mock one you create in your test isn't being used at all.
If possible, make the HbaseUtil1 object passable, or settable on the MessageProcessor1 class and then set it in the test class.
Also, and note I'm not 100% familiar with PowerMock, you could include HbaseUtil1 in the prepare for test annotation. I think that will make PowerMock instantiate mocks instead of real objects and then use the expectations you provide in you test.

Categories

Resources