Commit 23280afc authored by Julien LHERMITE's avatar Julien LHERMITE Committed by Colin DAMON

Java Trip service kata

parent 3c2dc075
......@@ -13,3 +13,4 @@ include:
- local: "/a-brief-history-of-date/.gitlab-ci.yml"
- local: "/mustache-replacer/.gitlab-ci.yml"
- local: "/string-calculator-2/.gitlab-ci.yml"
- local: "/trip-service-kata/.gitlab-ci.yml"
......@@ -31,5 +31,6 @@ Ce dépôt Git a pour but de partager les différents ateliers pouvant être ré
| [Une annonce pour recruter un crafter - Caroline, Chloé, Ianic et Colin](https://www.youtube.com/watch?v=E5AX6Ar1Fog) | Discussion | |
| [PadBowl](https://gitlab.com/cdamon/padbowl) | Application | Enervé |
| [A Brief History of Date](/a-brief-history-of-date) | Kata | Moyenne |
| [Trip service (Java)](/trip-service-kata) | Kata | Moyenne |
| [Mustache Replacer](/mustache-replacer) | Kata | Facile |
| [String calculator 2](/string-calculator-2) | Kata | Moyenne |
This diff is collapsed.
......@@ -10,6 +10,7 @@
"devDependencies": {
"husky": "1.3.1",
"lint-staged": "8.1.4",
"onchange": "^7.0.2",
"prettier": "^1.19.1",
"prettier-plugin-java": "^0.6.0"
},
......
package-trip-service-kata:
variables:
PROJECT_FOLDER: "trip-service-kata"
extends: .java
only:
refs:
- master
- merge_requests
changes:
- ".gitlab-common-ci.yml"
- "trip-service-kata/**/*"
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<version>1.0.0</version>
<groupId>fr.ippon.kata</groupId>
<artifactId>java-parent</artifactId>
<relativePath>../java-parent</relativePath>
</parent>
<version>1.0.0-SNAPSHOT</version>
<artifactId>trip-service-kata</artifactId>
<name>TripServiceKata</name>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0-M1</version>
<scope>test</scope>
</dependency>
</dependencies>
<developers>
<developer>
<email>jlhermite@ippon.fr</email>
<name>Julien LHERMITE</name>
</developer>
<developer>
<email>cdamon@ippon.fr</email>
<name>Colin DAMON</name>
</developer>
</developers>
</project>
# Trip service (java)
Découverte et résolution du kata [TripService](https://github.com/sandromancuso/trip-service-kata)
- **Auteur** : Julien LHERMITE et Colin DAMON
- **Date** : 20/10/2020
- **Langage** : Java
- **Niveau** : Moyen
- **Replay** : [Trip Service Kata (Java) avec Julien & Colin](https://www.youtube.com/watch?v=YIKI_-xqJfc)
# Testing legacy code: Hard-wired dependencies
Code related to my [Testing legacy code: Hard-wired dependencies][1] blog post. Try not reading the blog post before doing the exercise yourself.
## What is it about?
Provides an example of existing code that needs to be unit tested. But there is one rule:
> We can't change any existing code if not covered by tests. The only exception is if we need to change the code to add unit tests, but in this case, just automated refactorings (via IDE) are allowed.
Although this is a very small piece of code, it has a lot of the problems that we find in legacy code.
## Details
If you want to give it a go, the starting point is [TripServiceTest.java][3] and [TripService.java][4]. Try unit testing it following the rule above.
For future comparisions, when you are done, you can always check [TripService_Original.java][2]
[1]: http://codurance.com/2011/07/16/testing-legacy-hard-wired-dependencies/ "Testing legacy code: Hard-wired dependencies blog post"
[2]: https://github.com/sandromancuso/trip-service-kata/blob/master/java/trip-service-kata/src/main/java/org/craftedsw/tripservicekata/TripService_Original.java "TripService_Original.java"
[3]: https://github.com/sandromancuso/trip-service-kata/blob/master/java/trip-service-kata/src/test/java/org/craftedsw/tripservicekata/TripServiceTest.java "TripServiceTest.java"
[4]: https://github.com/sandromancuso/trip-service-kata/blob/master/java/trip-service-kata/src/main/java/org/craftedsw/tripservicekata/trip/TripService.java "TripService.java"
package org.craftedsw.tripservicekata;
import java.util.ArrayList;
import java.util.List;
import org.craftedsw.tripservicekata.exception.UserNotLoggedInException;
import org.craftedsw.tripservicekata.trip.Trip;
import org.craftedsw.tripservicekata.trip.TripDAO;
import org.craftedsw.tripservicekata.user.User;
import org.craftedsw.tripservicekata.user.UserSession;
public class TripService_Original {
public List<Trip> getTripsByUser(User user) throws UserNotLoggedInException {
List<Trip> tripList = new ArrayList<Trip>();
User loggedUser = UserSession.getInstance().getLoggedUser();
boolean isFriend = false;
if (loggedUser != null) {
for (User friend : user.getFriends()) {
if (friend.equals(loggedUser)) {
isFriend = true;
break;
}
}
if (isFriend) {
tripList = TripDAO.findTripsByUser(user);
}
return tripList;
} else {
throw new UserNotLoggedInException();
}
}
}
package org.craftedsw.tripservicekata.exception;
public class CollaboratorCallException extends RuntimeException {
private static final long serialVersionUID = -4584041339906109902L;
public CollaboratorCallException() {
super();
}
public CollaboratorCallException(String message,
Throwable cause) {
super(message, cause);
}
public CollaboratorCallException(String message) {
super(message);
}
public CollaboratorCallException(Throwable cause) {
super(cause);
}
}
package org.craftedsw.tripservicekata.exception;
public class UserNotLoggedInException extends RuntimeException {
private static final long serialVersionUID = 8959479918185637340L;
}
package org.craftedsw.tripservicekata.trip;
public class Trip {
}
package org.craftedsw.tripservicekata.trip;
import java.util.List;
import org.craftedsw.tripservicekata.exception.CollaboratorCallException;
import org.craftedsw.tripservicekata.user.User;
public class TripDAO implements Trips {
public static List<Trip> findTripsByUser(User user) {
throw new CollaboratorCallException("TripDAO should not be invoked on an unit test.");
}
@Override
public List<Trip> find(User user) {
return TripDAO.findTripsByUser(user);
}
}
package org.craftedsw.tripservicekata.trip;
import java.util.List;
import org.craftedsw.tripservicekata.exception.UserNotLoggedInException;
import org.craftedsw.tripservicekata.user.User;
import org.craftedsw.tripservicekata.user.UserSession;
public class TripService {
private final UserSession userSession;
private final Trips trips;
public TripService(UserSession userSession, Trips trips) {
this.userSession = userSession;
this.trips = trips;
}
public List<Trip> getTripsByUser(User user) throws UserNotLoggedInException {
User loggedUser = userSession.getLoggedUser();
assertUserIsAuthenticated(loggedUser);
return user
.getFriends()
.stream()
.filter(friend -> friend.equals(loggedUser))
.findFirst()
.map(friend -> findTrips(user))
.orElse(List.of());
}
protected List<Trip> findTrips(User user) {
return trips.find(user);
}
private void assertUserIsAuthenticated(User loggedUser) {
if (loggedUser == null) {
throw new UserNotLoggedInException();
}
}
}
package org.craftedsw.tripservicekata.trip;
import java.util.List;
import org.craftedsw.tripservicekata.user.User;
public interface Trips {
List<Trip> find(User user);
}
package org.craftedsw.tripservicekata.user;
import java.util.ArrayList;
import java.util.List;
import org.craftedsw.tripservicekata.trip.Trip;
public class User {
private List<Trip> trips = new ArrayList<Trip>();
private List<User> friends = new ArrayList<User>();
public List<User> getFriends() {
return friends;
}
public void addFriend(User user) {
friends.add(user);
}
public void addTrip(Trip trip) {
trips.add(trip);
}
public List<Trip> trips() {
return trips;
}
}
package org.craftedsw.tripservicekata.user;
import org.craftedsw.tripservicekata.exception.CollaboratorCallException;
public class UserSession {
private static final UserSession userSession = new UserSession();
private UserSession() {
}
public static UserSession getInstance() {
return userSession;
}
public User getLoggedUser() {
throw new CollaboratorCallException(
"UserSession.getLoggedUser() should not be called in an unit test");
}
}
package org.craftedsw.tripservicekata.trip;
class TripDAOTest {}
package org.craftedsw.tripservicekata.trip;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.when;
import java.util.List;
import org.craftedsw.tripservicekata.exception.UserNotLoggedInException;
import org.craftedsw.tripservicekata.user.User;
import org.craftedsw.tripservicekata.user.UserSession;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class TripServiceTest {
private final User authenticatedUser = new User();
private final User friend = new User();
@Mock
private UserSession userSession;
@Mock
private Trips trips;
@InjectMocks
private TripService service;
@BeforeEach
void loadAuthentication() {
when(userSession.getLoggedUser()).thenReturn(authenticatedUser);
}
@Test
void shouldNotGetTripsWithoutAuthenticatedUser() {
when(userSession.getLoggedUser()).thenReturn(null);
assertThatThrownBy(() -> service.getTripsByUser(authenticatedUser)).isExactlyInstanceOf(UserNotLoggedInException.class);
}
@Test
void shouldGetEmptyTripsForNewUser() {
assertThat(service.getTripsByUser(authenticatedUser)).isEmpty();
}
@Test
void shouldGetFriendTrips() {
friend.addFriend(authenticatedUser);
Trip tripToLasVegas = new Trip();
friend.addTrip(tripToLasVegas);
when(trips.find(friend)).thenReturn(List.of(tripToLasVegas));
assertThat(service.getTripsByUser(friend)).containsExactly(tripToLasVegas);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment