I am trying to init object with default if not initialized by the user.
I want the user be able not to add params in the request but I will have it with the default value.
I'm not sure what I am missing but I get Null Pointer exception.
Having this object
#Builder
#Data
#Valid
#RequiredArgsConstructor
#AllArgsConstructor
#NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
public class Request {
private final List<Author> authors;
private final Config config;
private Params params;
}
#Builder
#AllArgsConstructor
#NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
#Data
#Setter(AccessLevel.NONE)
public class Params {
#Builder.Default private boolean adultOnly = false;
}
fun main(args: Array<String>) {
val request = Request(
authors,
config(
key,
level
)
)
also using builder throw null exception
val request = QueriesRequest.builder()
.userQueries(userQueries)
.configurationKey(
QueryConfigurationKey(configurationKey,
granularityLevel))
.site(site).build()
request.params.adultOnly // throw NULL , I expected to have the default false.
}
What I am missing?
The params field in the Request class is never initialized and remains null. You could set a default value for it:
#Builder
#Data
#Valid
#RequiredArgsConstructor
#AllArgsConstructor
#NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
public class Request {
private final List<Author> authors;
private final Config config;
#Builder.Default
private Params params = Params.builder().build();
}
I'm using the Params' builder itself to initialize the default value, so that you will get the default values as defined by that builder as well.
Related
I got class:
public abstract class AbstractEntity {
#Getter
#Column(nullable = false, unique = true, updatable = false)
private UUID uuid = UUID.randomUUID();
}
and test:
def 'should be transitive: if x.equals(y) and y.equals(z) then x.equals(z)'() {
given:
AbstractEntity place = new Place()
AbstractEntity secondPlace = new Place()
AbstractEntity thirdPlace = new Place()
and: 'all entities has same uuid what makes them equal'
secondPlace.changeUuid(place.uuid)
thirdPlace.changeUuid(place.uuid)
line secondPlace.changeUuid(place.uuid) throws exception: groovy.lang.ReadOnlyPropertyException: Cannot set readonly property
How can I set this field value without using java reflection?
You seem to have an attribute in the #Column 'updatable = false. My first reaction is to think that this stops variables from being updated.
There is also no #Setter annotation which could be useful in this scenario.
Then you could use this method within your test.
I'm testing a post method in my controller that only return a String and using Mockito to mock the service call. My problem is that when the service method is called on controller it return null.
#RunWith(SpringRunner.class)
#WebMvcTest(ProcessGroupController.class)
public class ProcessGroupRestControllerTest {
.............
#Test
public void givenAllNifiArguments_whenImportProcessGroup_thenReturnJsonOk() throws Exception {
NiFiArguments niFiArguments = NiFiArguments.builder()......flowVersion("3").build();
String expected = "1689d61b-624d-4574-823d-f1b4755882e1";
String json = mapper.writeValueAsString(niFiArguments);
//Mock service call
when(nifiService.importProcessGroup(niFiArguments)).thenReturn(expected);
mvc.perform(post("/nifi/pg-import").contentType(MediaType.APPLICATION_JSON).content(json))
.andExpect(status().isCreated())......);
}
The controller:
#PostMapping("/pg-import")
public ResponseEntity<String> importProcessGroup(#RequestBody NiFiArguments niFiArguments)
throws NiFiClientException {
log.info("Called method importFlow");
String result = nifiService.importProcessGroup(niFiArguments);
return new ResponseEntity<String>(result, HttpStatus.CREATED);
}
String result = null
I have similar tests that return a POJO and it works perfectly
As ekalin said my builder class needed to implement equals and hashcode:
#Builder
#Getter
#EqualsAndHashCode
public class NiFiArguments {
private String bucketIdentifier;
private String flowIdentifier;
private String flowVersion;
private String baseUrl;
}
I try to mock a controller which contains a util method inside even though I mock the util method, the mvcMock ignore the result from the when(...) and call the method again with empty parameters which lead to nullpointerexception
How I can ship the call of
when(utilMock.getOperatorsAdNameWrapper(userName, adNames)).thenReturn(roleSet);
with the mockMvc.perform?
#GetMapping(value = {"/wellbore"})
public String wellboreForm(Model model, #RequestParam("mode") String mode, HttpServletRequest request) {
Set<String> operators = new LinkedHashSet<>();
String userName = (String) request.getSession().getAttribute("userName");
Set<String> operatorsSet = (HashSet<String>) request.getSession().getAttribute("userRoles");
Set<String> operatorsAdName = util.getOperatorsAdNameWrapper(userName, operatorsSet);
operatorsAdName.forEach(adName -> {
Query query = new Query()
.setClassname(Wellbore.CLASS)
.eq(Wellbore.operatorsGroup, adName);
operators.addAll(getWellboresNameList(query));
});
model.addAttribute("wellboreDataList", operators);
model.addAttribute("wellboreData", new WellboreForm());
return "ui/selectWellbore";
}
public static Set<String> getOperatorsAdName(String userName, Set<String> operatorsAdName) {
operatorsAdName.removeIf(x -> x.equals(userName)
|| x.equals("SCOUT")
|| x.equals("GTO")
|| x.equals("KADME")
|| x.equals("offline_access")
|| x.equals("uma_authorization"));
return operatorsAdName;
}
public Set<String> getOperatorsAdNameWrapper(String userName, Set<String> operatorsAdName) {
return getOperatorsAdName(userName,operatorsAdName);
}
#Mock
private Util utilMock;
#Test
#DisplayName("GET /wellbore - Select Wellbore")
void testMockMvc() throws Exception {
HttpServletRequest req = Mockito.mock(HttpServletRequest.class);
when(req.getAttribute("userName")).thenReturn("abcd");
String userName = (String) req.getAttribute("userName");
//Here I get the correct result Result
when(utilMock.getOperatorsAdNameWrapper(userName, adNames)).thenReturn(roleSet);
//another call made here with empy parameters to utilMock.getOperatorsAdNameWrapper("", null)
mockMvc.perform(get("/wellbore").param("mode","selectWellbore")
.sessionAttr("wellboreDataList", new LinkedHashSet<>())
.sessionAttr("wellboreData", new WellboreForm())
)
.andExpect(status().isOk())
.andExpect(view().name("ui/selectWellbore"))
.andExpect(model().attribute("wellboreDataList", hasSize(2)));
}
1) In the Controller move the line:
util.getOperatorsAdNameWrapper(userName, operatorsSet);
into a package level method:
Set<String> getOperatorsAdNameWrapper(userName, operatorsSet){
return util.getOperatorsAdNameWrapper(userName, operatorsSet);
}
2) In your test use SpyBean:
#SpyBean
private Controller controllerSpy;
#Test
#DisplayName("GET /wellbore - Select Wellbore")
void testMockMvc() throws Exception {
doReturn(roleSet).when(controllerSpy).getOperatorsAdNameWrapper(userName, adNames);
The general gist is that you cannot mock a static call with vanilla Mockito. You have to refactor a bit first.
The Problem was with the Util class
since I am using mockmvc as unit testing, not as integration test by standaloneSetup
mockMvc = MockMvcBuilders
//To avoid loading springContext
.standaloneSetup(controller)
.setViewResolvers(viewResolver())
.build();
so the Util class not loaded to the context to solve this you have to option
Move the wrapper method in the util class to the service class and from there you can wrapper the static method in the Util class
Add the util class to the controller constructor
I've my main class something like this:
class MyClass{
String bar(String inputString){
String url = "https:x.y.z/p/q"; //the URL is framed dynamically based on other class attributes
final String payloadInJson = getPayload(inputString)
final String response = doPostRequest(url, payloadInJson)
}
private static String doPostRequest(final String url, final String postData) throws IOException {
final RequestBody body = RequestBody.create(JSON, postData)
final Request request = new Request.Builder()
.url(url)
.post(body)
.build()
final Response response = createOkHttpClient().newCall(request).execute()
if (!response.isSuccessful()) {
throw new RuntimeException("...")
}
response.networkResponse().header("Location")
}
private static OkHttpClient createOkHttpClient() {
Config config = new ConfigBuilder()
.withTrustCerts(true)
.build()
def httpClient = HttpClientUtils.createHttpClient(config)
httpClient = httpClient.newBuilder().authenticator(Authenticator.NONE).build()
httpClient
}
}
and My Consumer test case is:
#SpringBootTest(classes = Application.class)
#AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL, ids = ["com.ex:foobar:+:stubs:8090"])
class MyClassTest{
#Inject
private MyClass myClass
def 'happyPath'(){
given:
...
when:
String res = myClass.bar('lorem...')
}
}
Question is how to mock the OkHttp URL and use localhost?
Or is it that in the test case, I can refer the actual URL framed?
If you use Spring Cloud Contract, we start an HTTP server on a given or random port. It's enough for you to set you OK Http Client to point to the started server. Example
PSEUDOCODE:
class MyClass{
private String url = "https:x.y.z/p/q";
String bar(String inputString){
final String payloadInJson = getPayload(inputString)
final String response = doPostRequest(this.url, payloadInJson)
}
// package scope
void setUrl(String url) {
this.url = url;
}
}
and in your test you can then set the stub's port and url
THE TEST (PSEUDOCODE AGAIN):
#SpringBootTest(classes = Application.class)
#AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL, ids = ["com.ex:foobar"])
class MyClassTest{
#Inject
private MyClass myClass
#StubRunnerPort("foobar") int stubPort;
def 'happyPath'(){
given:
myClass.url = "http://localhost:${stubPort}"
when:
String res = myClass.bar('lorem...')
}
}
a better option is to use a proper #Configuration class where you define beans and inject the URL via constructor. Anyways, hopefully, it shows you how you can approach the problem.
I have the below JSON code that needs to be parsed. I'm using the corresponding JAX-RS models. The problem is that the paymillClient object is null. If I add currency as a string inside the PaymillSubscription object, it returns EUR value, not null. So there appears to be a problem with the PaymillClient object, not plain strings. Could there be a limit to the number of nested objects for parsing ? Ex, max 2 nested objects. So because there are 3 in my case, it doesn't work.
Unfortunately, I cannot change the JSON code that needs to be parsed at all. I just need to make it work with the JAX-RS implementation.
{
"event":{
"event_type":"subscription.succeeded",
"event_resource":{
"subscription":{
"id":"sub_29f144a3bc32c71f96e2",
"offer":{ },
"livemode":false,
"amount":200,
"temp_amount":null,
"currency":"EUR",
"name":"Monthly subscription",
"interval":"1 MONTH",
"trial_start":null,
"trial_end":null,
"period_of_validity":null,
"end_of_period":null,
"next_capture_at":1428939744,
"created_at":1426264944,
"updated_at":1426264944,
"canceled_at":null,
"payment":{ },
"app_id":null,
"is_canceled":false,
"is_deleted":false,
"status":"active",
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
},
"transaction":{ }
},
"created_at":1426264944,
"app_id":null
}
}
PaymillEventContainer:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventContainer
{
private PaymillEvent event;
}
PaymillEvent:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEvent
{
#XmlElement(name = "event_type") #DocumentationExample(value = "subscription.succeeded") private String eventType;
#XmlElement(name = "event_resource") private PaymillEventResource eventResource;
}
PaymillEventResource:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillEventResource
{
private PaymillClient client;
private PaymillOffer offer;
private PaymillSubscription subscription;
}
PaymillSubscription:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillSubscription
{
private PaymillClient client;
private PaymillOffer offer;
}
PaymillClient:
#XmlAccessorType(XmlAccessType.FIELD)
public class PaymillClient
{
#DocumentationExample(value = "client_c0c24aa7f97e1b8ed15d") private String id;
}
API endpoint code:
public Response postSubscriptionSucceeded(PaymillEventContainer paymillEventContainer)
{
PaymillEvent paymillEvent = paymillEventContainer.getPaymillEvent();
PaymillEventResource paymillEventResource = paymillEvent.getEventResource();
PaymillSubscription paymillSubscription = paymillEventResource.getSubscription();
PaymillClient paymillClient = paymillSubscription.getPaymillClient();
PaymillOffer paymillOffer = paymillSubscription.getPaymillOffer();
String clientId = paymillClient.getId(); // NullPointerException
}
Ok. I tried to run your code on your machine and also received null (note, that I'm using MOXy to unmarshall JSON). Then, I tried to experiment with it a little and found really funny things:
1. If you will remove all null-valued fields from your JSON, all works just perfect.
2. If you will add another field to PaymillSubscription. I added private Test test, where Test is:
#XmlAccessorType(XmlAccessType.FIELD)
public class Test {
private String id;
}
And will send this "test" object between last null-valued field in subscription object and "client" field:
"test":{"id":"sadas"},
"client":{
"id":"client_c0c24aa7f97e1b8ed15d"
}
Then "test" would be null, but "client" will be parsed as expected.
3. If you will add all null-valued objects into model (I mean, create respective fields in PaymillSubscription class) all works just perfect.
It seems, that by default JAXB specification doesn't allow JSON with unrecognized fields, but MOXy still tries to parse it (and sometimes produces errors).