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

Us add payment entity 2 #48

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

Conversation

jluisbn
Copy link

@jluisbn jluisbn commented Aug 15, 2023

No description provided.

@jluisbn
Copy link
Author

jluisbn commented Aug 15, 2023

Screenshot for existing user and existing payment
Retrieve_found_payment

Screenshot for existing user but no payment found
Retrieve_no_found_payment

Screenshot for user not found
Retrieve_user_no_found

private final PaymentService paymentService;
private final UserValidator userValidator;

public PaymentController(PaymentService paymentService, UserValidator userValidator) {
Copy link
Member

Choose a reason for hiding this comment

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

Do you know about @RequiredArgsConstructor?

Copy link
Author

Choose a reason for hiding this comment

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

I do, I just forgot, and also tried to follow UserController convention as requested.

@ResponseBody
public List<PaymentDto> retrievePaymentsByUser(final @PathVariable String userId) {

log.info("Retrieving payments for user Id {}", userId);
Copy link
Member

Choose a reason for hiding this comment

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

Do you think this log belongs after the validation?

Copy link
Author

Choose a reason for hiding this comment

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

For sure, I just think I like to keep trail of everithing that happens, so it is easier to debug in my opinion.

@Repository
public interface PaymentRepository extends JpaRepository<Payment, String> {

List<Payment> findAllByUserId(String userId);
Copy link
Member

Choose a reason for hiding this comment

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

How is this different than findByUserId? Does findByIgnoreCase make sense here?

Copy link
Author

Choose a reason for hiding this comment

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

I just use that more descriptive even though it is the same result as byUserId. And about the ignoreCase, I think we should look for exact keys, and also we could face some performance issues if we start doing searches with ignore case, let's say we have an index in the userId, as far as I am concerned this type of searches would ignore the index and probably be an slow query.

}

public List<PaymentDto> retrieveByUserId(String userId) {
log.info("Retrieving all payments by user Id");
Copy link
Member

Choose a reason for hiding this comment

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

It doesn't make sense to have a log at the Controller and Service layers. You are not passing the userId into the log message.

Copy link
Author

Choose a reason for hiding this comment

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

Agreed, I just think I like to keep trail of everithing that happens, so it is easier to debug in my opinion.

public List<PaymentDto> retrieveByUserId(String userId) {
log.info("Retrieving all payments by user Id");

userRepository.findById(userId).orElseThrow(() -> new DataNotFoundException("User Id does not exist. Please validate input"));
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to declare a existsById query instead of doing a search to throw away the result. exists or count would be more efficient on the database. Alternatively do we need to check at all? Is it fine to return 0 payments when the userId provided does not exist?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, you are right, maybe I am to defensive so if something does not look right I rather throw an exception, and let the user give it another try.

('6033d04d-c602-4354-a411-d376a9215c68', 'f8bbbc7a-867b-4e8d-a2a5-8b7c07a4589c', '3997869182123667', 1, 2024, {ts '2020-11-12 11:22:15.264'}),
('dd52bd06-d337-4624-d9bf-9593f2cff4c1', '06c70a5b-1950-4765-81b6-4bb2378e0991', '8439375960556557', 2, 2026, {ts '2018-05-11 17:22:15.125'}),
('1628a7c9-ed7e-4582-eac6-b3321c2fdbe1', 'd54b6b5d-de10-4c06-9837-c7457937daf8', '5929456670566065', 3, 2025, {ts '2019-04-26 06:55:27.748'}),
('6931d250-f972-4c5b-fc65-85904473de56', 'f8160123-1766-41c7-8056-2acbfd3c4f2a', '2981890323295572', 7, 2024, {ts '2022-08-08 09:11:52.428'});
Copy link
Member

Choose a reason for hiding this comment

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

Can you explain this syntax? {ts '2023-07-01 07:20:16.267'} for the updated field?

Copy link
Author

Choose a reason for hiding this comment

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

I thought it was just a timestamp as when the user updated their information. Probably should I paid more attention to it.


assertNotNull(result);
assertNotNull(responseBody);
assertTrue(responseBody.contains("\"id\" : \"15040055-a640-4cea-cfb7-357669fcdefe\""));
Copy link
Member

Choose a reason for hiding this comment

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

You can chain the .getResponse().getContentAsString() onto result since the result variable is only used that 1 time.

final String responseBody = this.mockMvc
                .perform(get("/payment/retrieve/" + userId))
                .andExpect(status().isOk())
                .andReturn()
                .getResponse()
                .getContentAsString();
  • Why is the responseBody variable not final?
  • The assertNotNull(result) is not necessary because the creation of responseBody would cause a NPE
  • The assertNotNull(responseBody) is not necessary because the assertTrue would cause a NPE if the responseBody is null and the test will fail.

Have you heard of jsonpath? https://www.petrikainulainen.net/programming/spring-framework/integration-testing-of-spring-mvc-applications-write-clean-assertions-with-jsonpath/

Copy link
Author

Choose a reason for hiding this comment

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

You are right. Will keep that in mind.

private final UserRepository userRepository = mock(UserRepository.class);
private final ResourceMapper resourceMapper = mock(ResourceMapper.class);

private final PaymentService underTest = new PaymentService(
Copy link
Member

Choose a reason for hiding this comment

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

Why are you using mock and constructor instead of @MockBean, @Mock, and @InjectMocks?

Copy link
Author

Choose a reason for hiding this comment

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

This is just the way I have been doing this. But I think using annotations is a cleaner way.

final String userId = "user-id";

when(userRepository.findById(userId)).thenReturn(Optional.of(TestUtil.getUserData()));
when(paymentRepository.findAllByUserId(userId)).thenReturn(TestUtil.getPayments());
Copy link
Member

@wheeleruniverse wheeleruniverse Aug 17, 2023

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 looser matcher and a verify? Do you know the difference?

when(userRepository.findById(anyString())).thenReturn(Optional.of(TestUtil.getUserData()));

...

verify(userRepository).findById(userId);

Copy link
Author

Choose a reason for hiding this comment

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

In my opinion that depends, because if you have a more complex method then you have to mock every call or access to their properties, but if you send a complete object (not a mock) then your code will not throw a NPE, and instead of having many "when then" I think it is a bit cleaner to have real objects.
And about the verify, I forgot to add that, I tend to always add it.

List<PaymentDto> payments = underTest.retrieveByUserId(userId);

assertNotNull(payments);
assertEquals(payments.size(), 0);
Copy link
Member

Choose a reason for hiding this comment

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

What about assertEmpty?

Copy link
Author

Choose a reason for hiding this comment

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

I have not used that one, and since I tend to use Sonarlint to avoid this code smells, Intellij did not suggest that method.

userDto.setLastName("Ford");
userDto.setPhoneNumber("");

return new User(userDto);
Copy link
Member

Choose a reason for hiding this comment

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

Why did you create UserSaveDto instead of User directly? These variables can be final and if you use @Builder you can remove the variable altogether.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, I missed that one.

@wheeleruniverse
Copy link
Member

Thank you so much! I left some comments on the PR for your benefit. We don't expect any additional commits so don't feel obligated to do so. Let me know if you have any questions or comments. Please respond to the questions I left in your code if you wouldn't mind. I would love to get your thoughts.

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