-
Notifications
You must be signed in to change notification settings - Fork 41
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
base: main
Are you sure you want to change the base?
Conversation
private final PaymentService paymentService; | ||
private final UserValidator userValidator; | ||
|
||
public PaymentController(PaymentService paymentService, UserValidator userValidator) { |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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")); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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'}); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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\"")); |
There was a problem hiding this comment.
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 notfinal
? - The
assertNotNull(result)
is not necessary because the creation ofresponseBody
would cause a NPE - The
assertNotNull(responseBody)
is not necessary because theassertTrue
would cause a NPE if theresponseBody
isnull
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/
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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);
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about assertEmpty
?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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. |
No description provided.