I have written sample CRUD methods.I have written JUnit test cases for Service component but getting "address id not found.." when I run the test.
#Test
public void updateAddressTest() throws ResourceNotFoundException {
Optional<Person> p = Optional.ofNullable(new Person( "Pranya", "Pune"));
when(personRepository.existsById(1L)).thenReturn(true);
Optional<Address> address = Optional.ofNullable(new Address( "zzz", "hyd","tel","1234"));
when(repository.findById(1L)).thenReturn(address);
Address addr1 = new Address( "zzz", "hyd","tel","1234");
when(repository.save(addr1)).thenReturn(addr1);
Address add= service.updateAddress(new Long(1L), new Long(1L),addr1);
assertEquals(addr1,add );
}
#Service
public class AddressService {
#Autowired
private AddressRepository repository;
#Autowired
private PersonRepository personRepository;
public Address updateAddress(Long personId,
Long addressId,Address addrRequest) throws ResourceNotFoundException {
if (!personRepository.existsById(personId)) {
throw new ResourceNotFoundException("personId not found");
}
return repository.findById(addressId).map(address -> {
address.setCity(addrRequest.getCity());
address.setState(addrRequest.getState());
address.setStreet(addrRequest.getStreet());
address.setPostalCode(addrRequest.getPostalCode());
Person p = new Person();
p.setId(personId);
address.setPerson(p);
return repository.save(address);
}).orElseThrow(() -> new ResourceNotFoundException("address id not found.."));
}
}
Most likely repository.save(address) returns null. You are mocking the method, but only for the argument equal addr1. Inside the AddressService a different instanceof the address is created. I'm guessing that Address class does not implement equals method (or includes the person field in the implementation), so when(repository.save(addr1)).thenReturn(addr1) does not match the call and null is returned.
To solve the problem try using Mockito.doAnswer instead of the Mockito.when:
Mockito.doAnswer(invocation -> invocation.getArguments()[0]).when(repo).save(Mockito.any(Address.class));
Related
I am new to flink i am trying write junit test cases to test KeyedBroadCastProcessFunction. Below is my code ,i am currently calling the getDataStreamOutput method in TestUtils class and passing inputdata and patternrules to method once the input data is evaluated against list of pattern rules and if input data satisfy the condition i will get the signal and calling sink function and returning output data as string in getDataStreamOutput method
#Test
public void testCompareInputAndOutputDataForInputSignal() throws Exception {
Assertions.assertEquals(sampleInputSignal,
TestUtils.getDataStreamOutput(
inputSignal,
patternRules));
}
public static String getDataStreamOutput(JSONObject input, Map<String, String> patternRules) throws Exception {
env.setParallelism(1);
DataStream<JSONObject> inputSignal = env.fromElements(input);
DataStream<Map<String, String>> rawPatternStream =
env.fromElements(patternRules);
//Generate a key,value pair of set of patterns where key is pattern name and value is pattern condition
DataStream<Tuple2<String, Map<String, String>>> patternRuleStream =
rawPatternStream.flatMap(new FlatMapFunction<Map<String, String>,
Tuple2<String, Map<String, String>>>() {
#Override
public void flatMap(Map<String, String> patternRules,
Collector<Tuple2<String, Map<String, String>>> out) throws Exception {
for (Map.Entry<String, String> stringEntry : patternRules.entrySet()) {
JSONObject jsonObject = new JSONObject(stringEntry.getValue());
Map<String, String> map = new HashMap<>();
for (String key : jsonObject.keySet()) {
String value = jsonObject.get(key).toString();
map.put(key, value);
}
out.collect(new Tuple2<>(stringEntry.getKey(), map));
}
}
});
BroadcastStream<Tuple2<String, Map<String, String>>> patternRuleBroadcast =
patternStream.broadcast(patternRuleDescriptor);
DataStream<Tuple2<String, JSONObject>> validSignal = inputSignal.map(new MapFunction<JSONObject,
Tuple2<String, JSONObject>>() {
#Override
public Tuple2<String, JSONObject> map(JSONObject inputSignal) throws Exception {
String source =
inputSignal.getSource();
return new Tuple2<>(source, inputSignal);
}
}).keyBy(0).connect(patternRuleBroadcast).process(new MyKeyedBroadCastProcessFunction());
validSignal.map(new MapFunction<Tuple2<String, JSONObject>,
JSONObject>() {
#Override
public JSONObject map(Tuple2<String, JSONObject> inputSignal) throws Exception {
return inputSignal.f1;
}
}).addSink(new getDataStreamOutput());
env.execute("TestFlink");
}
return (getDataStreamOutput.dataStreamOutput);
}
#SuppressWarnings("serial")
public static final class getDataStreamOutput implements SinkFunction<JSONObject> {
public static String dataStreamOutput;
public void invoke(JSONObject inputSignal) throws Exception {
dataStreamOutput = inputSignal.toString();
}
}
I need to test different inputs with same broadcast rules but each time i am calling this function its again and again doing process from beginning take input signal broadcast data, is there a way i can broadcast once and keeping on sending the input to the method i explored i can use CoFlatMapFunction something like below to combine datastream and keep on sending the input rules while method is running but for this one of the datastream has to keep on getting data from kafka topic again it will overburden on method to load kafka utils and server
DataStream<JSONObject> inputSignalFromKafka = env.addSource(inputSignalKafka);
DataStream<org.json.JSONObject> inputSignalFromMethod = env.fromElements(inputSignal));
DataStream<JSONObject> inputSignal = inputSignalFromMethod.connect(inputSignalFromKafka)
.flatMap(new SignalCoFlatMapper());
public static class SignalCoFlatMapper
implements CoFlatMapFunction<JSONObject, JSONObject, JSONObject> {
#Override
public void flatMap1(JSONObject inputValue, Collector<JSONObject> out) throws Exception {
out.collect(inputValue);
}
#Override
public void flatMap2(JSONObject kafkaValue, Collector<JSONObject> out) throws Exception {
out.collect(kafkaValue);
}
}
I found a link in stackoverflow How to unit test BroadcastProcessFunction in flink when processElement depends on broadcasted data but this is confused me a lot
Any way i can only broadcast only once in Before method in test cases and keeping sending different kind of data to my broadcast function
You can use KeyedTwoInputStreamOperatorTestHarness in order to achieve this for example let's assume you have the following KeyedBroadcastProcessFunction where you define some business logic for both DataStream channels
public class SimpleKeyedBroadcastProcessFunction extends KeyedBroadcastProcessFunction<String, String, String, String> {
#Override
public void processElement(String inputEntry,
ReadOnlyContext readOnlyContext, Collector<String> collector) throws Exception {
//business logic for how you want to process your data stream records
}
#Override
public void processBroadcastElement(String broadcastInput, Context
context, Collector<String> collector) throws Exception {
//process input from your broadcast channel
}
Let's now assume your process function is stateful and is making modifications to the Flink internal state, you would have to create a TestHarness inside your test class to ensure you are able to keep track of the state during testing.
I would then create some unit tests using the following approach:
public class SimpleKeyedBroadcastProcessFunctionTest {
private SimpleKeyedBroadcastProcessFunction processFunction;
private KeyedTwoInputStreamOperatorTestHarness<String, String, String, String> testHarness;
#Before
public void setup() throws Exception {
processFunction = new SimpleKeyedBroadcastProcessFunction();
testHarness = new KeyedTwoInputStreamOperatorTestHarness<>(
new CoBroadcastWithKeyedOperator<>(processFunction, ImmutableList.of(BROADCAST_MAP_STATE_DESCRIPTOR)),
(KeySelector<String, String>) string -> string ,
(KeySelector<String, String>) string -> string,
TypeInformation.of(String.class));
testHarness.setup();
testHarness.open();
}
#After
public void cleanup() throws Exception {
testHarness.close();
}
#Test
public void testProcessRegularInput() throws Exception {
//processElement1 send elements into your regular stream, second param will be the event time of the record
testHarness.processElement1(new StreamRecord<>("Hello", 0));
//Access records collected during processElement
List<StreamRecord<? extends String>> records = testHarness.extractOutputStreamRecords();
assertEquals("Hello", records.get(0).getValue())
}
#Test
public void testProcessBroadcastInput() throws Exception {
//processElement2 send elements into your broadcast stream, second param will be the event time of the record
testHarness.processElement2(new StreamRecord<>("Hello from Broadcast", 0));
//Access records collected during processElement
List<StreamRecord<? extends String>> records = testHarness.extractOutputStreamRecords();
assertEquals("Hello from Broadcast", records.get(0).getValue())
}
}
I have an application where I have an html page which takes user input through a textbox.This is a REST Spring Framework and is divided as Controller, Entity, Service, Repository, View and the main application class.
I take an input value and search in the Mongodb database, If the value is present, I return the entity object from Service to Controller. The controller returns the same Entity View object.- PersonView in this case. I get a JSON Data.
The above scenario works well as long as there are records in the database. In case if the record is not present, it returns an empty JSON. My Controller returns Person View Object and I do not wish to change the signature and make the return type as String since in that case it returns the address on my HTML page.
Considering this, how should I handle the case when there are no records in the database and I wish to display a message on this same HTML page saying there are no records available.
I tried throwing an exception but in this case too, how Do I display message on my HTML considering that my Controller returns JSON object and I do not wish to change its signature?
Controller Class is as below:
public PersonView searchPerson(#PathVariable String pname) {
List<Person> pList= PersonService.searchPerson(pname);
PersonView personView = new PersonView();
personView.setPersonView(pList);
return personView;
EDIT:
Here is the function from personView Class that I call in Controller:
public List<Person> setPersonView() {
this.personView = personView;
}
Here is the service Impl class:
public List<Person> searchPerson(String name) throws Exception {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty())
throw new Exception("Records not found in the the database");
return personlist;
}
Create a custom Exception class:
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}
Now, in you controller code:
public List<Person> searchPerson(String name) {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty()) {
throw new EntityNotFoundException("Records not found in the the database");
}
return personlist;
}
After that you can try something like this in you controller class:
private static final MappingJacksonJsonView JSON_VIEW = new MappingJacksonJsonView();
#ExceptionHandler(EntityNotFoundException.class)
public ModelAndView handleNotFoundException( Exception ex )
{
return new ModelAndView(JSON_VIEW, "error", new ErrorMessage("No Record in Db") );
}
Your ErrorMessage class can be a simple POJO:
public class ErrorMessage {
private String message;
ErrorMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
Although already answered, I will add some points here.
Please note that at some point of time you will have a requirement to send the
headers, Response body (with different Objects). So consider using ResponseEntity Object which will be a wrapper to your List. Here is the sample code.
public ResponseEntity<List<Person>> searchPerson(String name) {
List<Person> personlist= new ArrayList<Person>();
personlist = personRepository.findByName(name);
if (personlist.isEmpty()) {
return new ResponseEntity(new EntityNotFoundException("Records not found in the the database"), HttpStatus.BAD_REQUEST);
}
return new ResponseEntity(personlist , HttpStatus.OK);
}
Response Entity Object provides flexibility to greater extent. Read the documentation here.
https://docs.spring.io/spring/docs/current/javadocapi/org/springframework/http/ResponseEntity.html
I need help for below thing,
I have to write a Junit using PowerMock/Mockito for a method which makes a call to a static method of a final class present in an external jar.
The method for which i need to write the JUnit test is:
public class SomeClass {
private PrivateKey privateKeyFromPkcs8(String privateKeyPem) throws IOException {
Reader reader = new StringReader(privateKeyPem);
Section section = PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY");
if (section == null) {
throw new IOException("Invalid PKCS8 data.");
}
byte[] bytes = section.getBase64DecodedBytes();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
try {
KeyFactory keyFactory = SecurityUtils.getRsaKeyFactory();
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (NoSuchAlgorithmException exception) {
} catch (InvalidKeySpecException exception) {
}
throw new IOException("Unexpected exception reading PKCS data");
}
}
In the above code PemReader is a final class and readFirstSectionAndClose(reader, "PRIVATE KEY") is a static method in PemReader.
I have tried writing the test shown below but Section object(section) is showing as null while debugging. Perhaps the actual code (PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY")) is getting called instead of the mock.
#RunWith(PowerMockRunner.class)
#PrepareForTest({SomeClass.class,PemReader.class})
public class SomeClassTest {
#InjectMocks
SomeClass mockSomeClass;
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testPrivateKeyFromPkcs8() throws Exception {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
assertNotNull(mockSomeClass.privateKeyFromPkcs8(dummyPrivateKey));
}
}
Please help me in writing a Junit using powermockito/mockito
You have to prepare the final, static class.
Here's an example using the PowerMock annotations for JUnit:
#RunWith(PowerMockRunner.class)
#PrepareForTest({PemReader.class})
public class PemReaderTest {
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testMockingStatic() {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
Assert.assertEquals(mockSection, PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY"));
}
}
For completeness, here's the definition of PemReader:
public final class PemReader {
public static Section readFirstSectionAndClose(Reader reader, String key) {
return null;
}
}
The above test passes with the following versions:
JUnit: 4.12
Mockito: 2.7.19
PowerMock: 1.7.0
Update 1: based on your updated question. Your test case will pass (or at least the invocation on PemReader.readFirstSectionAndClose will return something) if you just make this change:
Mockito.when(PemReader.readFirstSectionAndClose(
Mockito.any(Reader.class),
Mockito.eq("PRIVATE KEY"))
).thenReturn(mockSection);
The version of this instruction in your current test case relies on equality matching between the StringReader which your code passes into readFirstSectionAndClose and the mocked Reader which your test case supplies. These are not 'equal' hence the mocked invocation's expectations are not met and your mockSection is not returned.
A few, unrelated, notes:
There is no need to include SomeClass.class in #PrepareForTest, you only need to include the classes which you want to mock in that annotation, since SomeClass is the class you are trying to test there is no mocking required for that class.
Using #InjectMocks to instance SomeClass is a bit odd, since SomeClass has no (mockito provided) mocks to inject into it :) you can replace this declaration with SomeClass someClass = new SomeClass();
In the code you supplied SomeClass.privateKeyFromPkcs8 has private scope so it cannot be tested (or called in any way) from SomeClassTest.
I have this custom matcher:
public class CofmanStringMatcher extends TypeSafeMatcher<String> {
private List<String> options;
private CofmanStringMatcher(final List<String> options) {
this.options = Lists.newArrayList(options);
}
#Override
protected boolean matchesSafely(final String sentResult) {
return options.stream().anyMatch(option -> option.equals(sentResult));
}
public static CofmanStringMatcher isCofmanStringOnOfTheStrings(List<String> options) {
return new CofmanStringMatcher(options);
}
#Override
public void describeTo(final Description description) {
System.out.println("in describeTo");
// description.appendText("expected to be equal to of the list: "+options);
}
}
which compares a string to few options for strings.
when i run this test code:
verify(cofmanService, times(1))
.updateStgConfigAfterSimulation(argThat(isCofmanStringOnOfTheStrings(ImmutableList.of(expectedConditionsStrings , expectedConditionsStrings2))), eq(Constants.addCommitMsg+SOME_REQUEST_ID));
I get this error:
Comparison Failure: <Click to see difference>
Argument(s) are different! Wanted:
cofmanService.updateStgConfigAfterSimulation(
,
"add partner request id = 1234"
);
-> at com.waze.sdkService.services.pubsub.callback.RequestToCofmanSenderTest.localAndRtValidationSucceeds_deployCofmanStg(RequestToCofmanSenderTest.java:131)
Actual invocation has different arguments:
cofmanService.updateStgConfigAfterSimulation(
"some text"
);
The test fails even though the method updateStgConfigAfterSimulation calls with 1st arg that matches on of the list elements
I'm using
mockito 1.10 and hamcrest 1.3
here is the method's signature
void updateStgConfigAfterSimulation(String conditionsMap, String commitMsg) throws Exception
I'm trying to do the Mockito for a method called generateToken() by using MockitoJUnitRunner.class. The source which I have tried to do as follows.
#RunWith(MockitoJUnitRunner.class)
public class LoginServiceTest {
#Mock
private UserRepository userRepository;
#Mock
private JwtTokenGenerator jwtTokenGenerator;
#InjectMocks
private LoginServiceImpl loginServiceImpl = new LoginServiceImpl();
private JwtUserDto user;
private String jwtSecret;
private String username;
private String password;
/**
* Initialize test data before test cases execution
*/
#Before
public void init() {
user = new JwtUserDto();
user.setId(1L);
user.setUsername("kray1");
user.setRole("Admin");
}
#Test
public void testLogin() {
try {
Mockito.when(jwtTokenGenerator.generateToken(user, jwtSecret)).thenReturn("myToken");
String actual = loginServiceImpl.login(username, password);
assertNotNull(actual);
} catch (Exception e) {
e.printStackTrace();
}
}
For that generateToken() method, I have to pass user object and a string. I'm declaring the user object in Init() method. When I try to execute this, the value return from the login method is null. But when I try to pass the user object as null then it will work as expected. So the problem should be with the user object.
Is there anything, like Mockito is blocking this kind of object with added properties or related thing? Please help to find a way to pass this user object with Mockito.
The LoginServiceImpl class as follows.
public class LoginServiceImpl implements LoginInterface {
#Autowired
private UserRepository userRepository;
#Autowired
private JwtTokenGenerator jwtTokenGenerator;
/*
* (non-Javadoc)
*/
public String login(String userName, String password) {
if (userName != null && password != null && !userName.isEmpty() && !password.isEmpty()) {
List<UserAuthenticationInfo> authInfo = userRepository.findUserRolesByUsernamePassword(userName, password);
if (authInfo != null && !authInfo.isEmpty()) {
JwtUserDto user = new JwtUserDto();
user.setId((long) authInfo.get(0).getUserId());
user.setUsername(userName);
user.setRole(authInfo.get(0).getUserRole());
return jwtTokenGenerator.generateToken(user, jwtSecret);
}
}
return null;
}
}
Do you have equals/hashcode on User class?
What is the result if you setup mock using
Mockito.when(jwtTokenGenerator.generateToken(any(User.class),any(String.class))
.thenReturn("myToken");
explanation:
When setting expectation as
Mockito.when(jwtTokenGenerator.generateToken(user, jwtSecret)).then...
You instruct your mock to act only for given user object. equals method is used for that. So, if your User is missing equals method, then reference equality is used. Two User objects (each crated with separate new User() call will not be equal.
For non-matching parameters in Mockito.when your mock (thenReturn) is not applied. Default value (null) is returned from mock.
Therefore I prefer to setup mocks not for specific arguments and then use Mockito.verify to check if expected interactions with mock took place. That way your tests are more expressive. Actually most of my object have equals/hashode not because of business reasons (I do not put them in collections) but only for testing and comparing using assertEquals.
Side note:
do not catch (Exception e) { e.printStackTrace(); } in test. It is much easier just to declare test method to throw Exception. End result is same (stacktrace printed) but with less code.
You are probably creating a new JwtUserDto() in your production code or getting the user instance from another mock. If you haven't overwritten the equals() method in your JwtUserDto class your 'test' user won't equal the 'production' user.
Make sure that the production and test user are the same instance or that they .equals each other.