JAXRS + JerseyTest测试REST服务 [英] JAXRS + JerseyTest testing a REST Service

查看:85
本文介绍了JAXRS + JerseyTest测试REST服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用GET,POST,UPDATE和DELETE四种方法创建了Rest服务. 这些方法建立与数据库的连接以检索和存储数据.

I've created a Rest service with four methods, GET,POST,UPDATE and DELETE. These methods make connections to a Database to retrieve and store data.

现在我要测试每种方法.我为此使用了Jersey测试框架.只要删除代码,真正对数据库进行调用的代码就可以正常工作.当我留下进行数据库调用的代码时,它抛出了一个异常,即它无法连接到数据库.

Now I want to test each method. I've used the Jersey Test Framework for this. And it is working as long as I remove the code what actually makes the call to the database. When I leave the code that makes the call to the database it throws an exception that it could not connect to the database.

我已经做了一些研究,并使用了依赖注入.数据库调用被移到一个单独的类,但是我仍然在做错什么.

I have done some research and used dependancy injection. The db calls are moved to a separate class but I'm still doing something wrong.

数据库结果.在此类中,将调用数据库.

DatabaseResults. In this class the call to the DB is made.

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;
    }
}

包含REST方法的MoviesResource

MoviesResource that contains the REST methods

@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();
}

测试类

@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));
}

这时我可以运行测试,但是当我测试getAllMovies()方法时,它仍然会调用真实的数据库,而不是返回jsonObject.

At this moment I can run the tests but still when I test the getAllMovies() method it makes a call to the real database instead of returning the jsonObject.

我感觉到模拟对象和MovieResource类的构造函数之间缺少连接吗?

I have the feeling that a connection is missing between the mock object and the constructor from the MovieResource class?

推荐答案

将资源注册为类时

new ResourceConfig(MoviesResource.class)

您正在告诉Jersey创建实例.如果您没有配置任何DI,它将仅调用no-arg构造函数.在您的无参数构造函数中,您只是自己创建服务.它对您的模拟游戏一无所知.

you are telling Jersey to create the instance. If you don't have any DI configured, it will just call the no-arg constructor. In your no-arg constructor, you are just creating the service yourself. It knows nothing about your mock.

您应该做的是将资源类注册为实例.这样,您就可以将模拟传递给构造函数.

What you should do instead is register the resource class as an instance. That way you can pass the mock to the constructor.

MockitoAnnotations.initMocks(this);
return new ResourceConfig()
        .register(new MoviesResource(dbr));

请勿使用Mockito运行器.而是使用MockitoAnnotations.initMocks方法.这样,您可以控制何时注入@Mock.如果使用流道,则注入不会及时发生,因为configure方法是在Mockito注入发生之前由框架调用的.

Don't use the Mockito runner. Instead use the MockitoAnnotations.initMocks method. That way you control when the @Mocks are injected. If you use the runner, the injection will not happen in time, as the the configure method is called by the framework before the Mockito injection happens.

这篇关于JAXRS + JerseyTest测试REST服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆