Ich habe einen Rest-Dienst mit vier Methoden erstellt, GET, POST, UPDATE und DELETE. Diese Methoden stellen Verbindungen zu einer Datenbank her, um Daten abzurufen und zu speichern.JAXRS + JerseyTest einen REST-Dienst testen
Jetzt möchte ich jede Methode testen. Ich habe das Jersey Test Framework dafür verwendet. Und es funktioniert so lange, wie ich den Code entferne, der tatsächlich den Anruf zur Datenbank macht. Wenn ich den Code belasse, der den Aufruf an die Datenbank sendet, löst er eine Ausnahme aus, die keine Verbindung zur Datenbank herstellen konnte.
EDIT: Ich habe ein wenig Forschung und verwendet Dependance-Injektion. Die DB-Aufrufe werden in eine separate Klasse verschoben, aber ich mache immer noch etwas falsch.
DatabaseResults. In dieser Klasse wird der Aufruf an die DB vorgenommen.
public class DatabaseResults {
private final String getQuery = "SELECT * FROM movies";
private Connection connection = null;
private PreparedStatement pstmt = null;
private final ArrayList<Movie> jsonList = new ArrayList<>();
public JSONObject getAllMovies() throws SQLException {
try {
ComboPooledDataSource dataSource = DatabaseUtility.getDataSource();
connection = dataSource.getConnection();
pstmt = connection.prepareStatement(getQuery);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
jsonList.add(new Movie(rs.getString(1), rs.getString(2), rs.getString(4), rs.getString(3)));
}
} catch (SQLException ex) {
System.out.println(ex);
System.out.println("Could not retrieve a connection");
connection.rollback();
} finally {
connection.close();
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("movies", jsonList);
return jsonObject;
}
}
MoviesResource, die die REST Methoden
@Path("movies")
public class MoviesResource {
....
private DatabaseResults dbResults = null;
public MoviesResource() {
this(new DatabaseResults());
}
MoviesResource(DatabaseResults dbr){
this.dbResults = dbr;
}
....
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getAllMovies() throws JSONException, SQLException {
return Response.status(200).entity(dbResults.getAllMovies().toString()).build();
}
Die Test-Klasse
@RunWith(MockitoJUnit44Runner.class)
public class MovieResourceTest extends JerseyTest {
JSONObject jsonObject = new JSONObject();
@Mock
DatabaseResults dbr;
@Before
public void setup() throws SQLException{
jsonObject.put("id", "hello");
when(dbr.getAllMovies()).thenReturn(jsonObject);
}
Client client = ClientBuilder.newClient();
WebTarget target = client
.target("http://localhost:9998/RestServiceMovies/resources");
@Override
protected Application configure() {
return new ResourceConfig(MoviesResource.class);
}
@Test
public void getAllMoviesTest() throws SQLException {
String responseGetAllMovies = target("/movies").request().get(String.class);
Assert.assertTrue("hello".equals(responseGetAllMovies));
}
In diesem Moment enthält ich die Tests ausführen kann, aber immer noch, wenn ich die getAllMovies()
Methode testen macht es einen Anruf in die echte Datenbank statt die jsonObject
zurückgeben.
Ich habe das Gefühl, dass eine Verbindung zwischen dem Mock-Objekt und dem Konstruktor aus der MovieResource-Klasse fehlt?
Dies ist schwieriger zu testen, da Ihr REST-Dienst das Prinzip der einheitlichen Verantwortlichkeit verletzt. Wenn Sie Ihre Datenbanklogik in einer anderen Klasse kapseln, können Sie diese Klasse einfach zum Schein testen, um den REST-Dienst isoliert zu testen. Ein anderer allgemeiner Ansatz besteht darin, das Fenster zu testen und nur Integrationstests durchzuführen. d. h. eine In-Memory-Datenbank konfigurieren und nichts vortäuschen. – DavidS
Ok. Also habe ich meine Datenbanklogik in einer separaten Klasse gekapselt. Ich möchte die Daten mit Mockito verspotten, aber ich bin mir eigentlich nicht sicher, wie ich sagen kann, dass meine 'getAllMovies'-Methode die gespottete Klasse verwenden soll ... – RSSD
Dort gibt es ein paar Ansätze dazu. Ich nehme an, dass Ihr REST-Dienst Zugriff auf ein privates Feld hat, z. 'FilmeDatenbank'. Sie möchten dieses Objekt oder seine Methoden vortäuschen, also benötigen Sie eine Möglichkeit, dem REST-Dienst mitzuteilen, welche 'moviesDatabase' verwendet werden soll. Ihre Optionen sind: (1) Konstruktorinjektion (2) mache das Feld package-private und setze es direkt (3) verwende ein fantastisches Abhängigkeitsinjektions-Framework wie Dolch oder Weld. – DavidS