Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trello ticket 13 - candidate-sample-payment-addition #32

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

ers020
Copy link
Contributor

@ers020 ers020 commented Aug 8, 2022

Notes on Changes:

pom.xml - I had been talking with Justin a while back, and he had mentioned the plugin pittest, so having tried it on my own, I decided to add it to this project to show the coverage of the Controller and Service I added (screen shots attached).

PaymentController - I added the requested GET method, and added a POST that consumes a Filter object. I figured it would be good for future code expansion possibilities. I understand this wasn't a requirement of the task, but wanted to expand it (screen shots for both attached).

ResourceMapper - I changed 1 line of code/logic, because when I went to test my initial code, I noticed it was returning the last 5 digits of the card number, instead of the last 4.

PageUtil - Made an overloaded method (no args) for the PageUtil to cut down on passing null values (more geared toward unit test coding).

data.sql - Added 6 entries for the payment table (attempted to mock the style of data being used in the program) and added 2 payment methods to the same User Id (grouped together at the top of the inserts) to show more than 1 return can happen.

getPaymentCall1
getPaymentCall1-2
Pit-Test_PaymentController
Pit-Test_PaymentService
postPaymentCall1
postPaymentCall1-2

@ers020
Copy link
Contributor Author

ers020 commented Aug 8, 2022

PaymentDto - Added the userId variable to show that the correct User information was being sent back in the response. Also included the single constructor arg to easily create the test object instead of having repeated code in multiple files.

Comment on lines 20 to 23
public PaymentDto(final String id) {
this();
this.id = id;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any other properties in here that should be required or added to the constructor. Setting final here when there is a setter from @DaTa annotation seems to only protect the value in certain situations. Is there a path to full immutability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor was mainly created to simplify code used in other places as a code cleanup effort; cleaner than using no args and setter. As far as making it more immutable, I can look into that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am pretty new with lombok (only heard about it a week ago), so I did some digging on the @builder. It looks like this would be a better alternative in the code in terms of creating objects with specific values, and won't clutter up the class I am trying to instantiate with values.

Though I did read a little more and saw @value, which does the same thing as @DaTa, but it makes the Class or Method fully immutable. I don't think this would be a good thing to do for the types of classes I am using (granted, @builder can make a referenced version I could use, but there would be a lot of recoding I would need to do at the moment), but the idea behind this is interesting, and something I wouldn't mind trying out in my free time.

If this isn't what you were looking for, let me know and I will do more research. I will also read up more on lombok and try some examples in my free time to see if it would be possible to update it to @value and be functional.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly :) . @value or an Immutable @builder would be my preference here. If there are multiple levels to the object, builders can have objects that are made with builders as subclasses (though that can get ugly fast).

Comment on lines 12 to 13
@AllArgsConstructor
@NoArgsConstructor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this being new, is there a reason for it having a builder a constructor and setters? Having three ways to set values seems overkill.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AllArgsConstructor was needed in order to create the object in the retrievePaymentByUserId on line 39 in the PaymentService class.

NoArgsConstructor - needed to stop an issue with serialization of the filter request object, it would return a Bad Request due to the application not being able to deserialize the object. Error from terminal: (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator).

I could get rid of the AllArgsConstructor by initializing an instance of the
object and then just using a setter, but the code does look cleaner this way.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code generators like Lombok are a toss up. In this case, it's autogen needs to match the serialization. My preference has evolved to using immutable builders in this situation and configuring the serialization to use builders. The main idea here is to pick one way to set the values and stick to it. Someone copied a few pages from effective java here https://cs108.epfl.ch/archive/19/c/i/EffectiveJava_Item17.pdf. I highly recommend the book. It helped my view of Java coding immensely. The goal should be immutable value objects.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the share, I will read this and take a look at getting the book (always room for learning more).

final PageRequest pageRequest,
final HttpServletResponse httpResponse
){
LOGGER.info("Request to retrieve payment information being conducted... paymentFilter: {}", filter);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of string formatting for the logger. This log message doesn't seem INFO to me. There are some reasons to log like this. Not sure they apply here. Would like to know what your thinking was.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logger is kind of a habit I have from when I worked at Verizon (their in home standard). It was required in the service area anytime something came in or went out, in the hopes of trouble shooting problems that may arise either from front end or the database. I could change it to Trace or Debug though.

Comment on lines +13 to +15
public static PageRequest createPageRequest() {
return createPageRequest(null, null);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it is only used for test code. In general, having nulls can create additional checks that need to happen in code. Since this is only in test, could the other initializer be used with hardcoded values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was more of a code cleanup effort from having null values in tests to acquire default values from the PageUtil (page 1, size 20). Just a personal choice, but the original call could still be used, and this removed.

}

@Test
public void getRetrieveWithUserId() throws Exception {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the throws needed here?

Copy link
Contributor Author

@ers020 ers020 Aug 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is to cover the .perform, and result.andExpect calls as both throw exceptions. I could wrap these into a try/catch block, but this makes the code cleaner.

private static final ObjectMapper MAPPER = new ObjectMapper();

@Autowired
private MockMvc mockMvc;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to see mockmvc. That is often missed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, it's been a little while since I have done JUnits and Mockito, so I am trying to do more learning and example coding in my free-time.

Comment on lines +84 to +86
public void postRetrieveWithFilter() throws Exception {
when(paymentService.retrieve(any(PaymentFilter.class), any(PageRequest.class), any(HttpServletResponse.class)))
.thenReturn(payments);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which layers are being tested with this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the flow of the Controller, as the mock is designed to merely mock the results of calling the Service class.

Comment on lines 53 to 56
final List<Integer> ids = IntStream
.range(1,6)
.boxed()
.collect(Collectors.toList());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this better than a simple List.of ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I keep forgetting List.of is an item of Java9 and above. I am used to mainly working in Java8. I will look into it and see which performs better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like in this scenario, List.of(), would be better; given that the amount of data is smaller and has no reason to be changed (since it is immutable).

Comment on lines 135 to 140
private Payment createPayment(String paymentId)
{
final Payment payment = new Payment();
payment.setId(paymentId);
return payment;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my view, this is too much work to make a payment object. The constructor or builder can be better alternatives.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. This is an oversight on my part. I will look into improving this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The @builder seems to be a good option for here, rather than what I did before with creating a single arg constructor, it's less messy than potentially having to add more constructors if I need to just set specific values.

@ers020
Copy link
Contributor Author

ers020 commented Aug 10, 2022

I will do the updates I have mentioned in my responses and push the code up by tomorrow. Thank you for the feedback so far.

@ers020
Copy link
Contributor Author

ers020 commented Aug 10, 2022

I pushed up fixes to use .builder() for some of the items, List.of() for another, and changing the the logger from INFO to DEBUG. I am going to work on immutable items for the PaymentFilter and see what I can do with the Payment DAO object.

@ers020
Copy link
Contributor Author

ers020 commented Aug 10, 2022

I was able to remove the Constructor I added to the PaymentDTO, make the PaymentFilter more immutable and took care of the serialization issue by using the @Jacksonized annotation (which provides an auto-generated deserizable class). Will focus on Payment Dao object now.

… but tests correctly and runs live correctly as well.
@ers020
Copy link
Contributor Author

ers020 commented Aug 10, 2022

Was able to get rid of the 1 arg constructor I made to make a Payment Dao that I needed by adding @builder. Ran into an issue with the mapperFacade, so I added the @AllArgsConstructor so reflection would work properly (converting Dao to Dto object). I will look a bit more before the night is over to see what I can come up with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants