Servletクラスのテスト

目的

JSONを返却するServletクラスの単体テストがしたい。

概要

  • GETメソッドのサーブレット
    • doGetをたたく
    • 引数にはMockHttpServletRequest, MockHttpServletResponseを利用
  • Connectionはデータソースを利用
    • PowerMockでモック
      • JUnitのTheoryも併用

検証プログラム

概要

  • idを渡して該当するレコードの内容をJSON形式で返却する
  • 該当idがない場合は空オブジェクトを返却する
  • DBデータ(テーブル:voiceact)
uid uname age office
aimi 愛美 26
goto 後藤沙緒里 31 null

ソース

サーブレット

package kurukuruz.sample.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kurukuruz.sample.servlet.connection.ConnectionPool;
import kurukuruz.sample.servlet.util.User;
import net.arnx.jsonic.JSON;

/**
 * Servlet implementation class Search
 */
@WebServlet(name = "search", urlPatterns = { "/search" })
public class Search extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
    * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
    */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // パラメータ取得
        String id = request.getParameter("id");

        // 検索実行
        User user = searchById(id);

        // JSON作成
        String result = "{}";
        if(user != null){
            result = JSON.encode(user);
        }

        // 返却
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter pw = response.getWriter();
        pw.print(result);
    }

    private User searchById(String id){
        User user = null;

        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = ConnectionPool.getConnection();

            String sql =
                    "SELECT uname, age, office "
                    + "FROM voiceact "
                    + "WHERE uid = ?";

            ps = conn.prepareStatement(sql);
            ps.setString(1, id);

            ResultSet rs = ps.executeQuery();
            if(rs.next()){
                user = new User(rs.getString(1), rs.getInt(2), rs.getString(3));
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            if(ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }


        return user;
    }

}

テストクラス

package kurukuruz.sample.servlet;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;

import javax.servlet.ServletException;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Setter;
import kurukuruz.sample.servlet.connection.ConnectionPool;
import kurukuruz.sample.servlet.testbase.ServletTestBase;
import net.arnx.jsonic.JSON;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(Theories.class)
@PrepareForTest({ConnectionPool.class})
public class SearchTest extends ServletTestBase {

    @DataPoints
    public static final Fixture[] fixtures = {
        new Fixture("aimi", "愛美", new BigDecimal(26), "響", false),
        new Fixture("goto", "後藤沙緒里", new BigDecimal(31), null, false),
        new Fixture("ayasa", null, null, null, true),
        new Fixture("", null, null, null, true),
        new Fixture(null, null, null, null, true),
    };

    @Theory
    @Test
    public void test(Fixture fixture) throws ServletException, IOException {
        MockHttpServletRequest req = new MockHttpServletRequest();
        MockHttpServletResponse res = new MockHttpServletResponse();

        req.setParameter("id", fixture.id);

        Search target = new Search();
        target.doGet(req, res);

        @SuppressWarnings("rawtypes")
        Map result = JSON.decode(res.getContentAsString());

        if(fixture.isEmpty){
            assertTrue("Mapの空判定", result.isEmpty());
        }else{
            assertThat("name判定", result.get("name"), is(fixture.name));
            assertThat("age判定", result.get("age"), is(fixture.age));
            assertThat("pc判定", result.get("pc"), is(fixture.pc));
        }
    }

    @Ignore
    @NoArgsConstructor
    @AllArgsConstructor
    @Setter
    public static class Fixture {
        // 検索条件
        private String id;
        // 想定結果
        private String name;
        private BigDecimal age;
        private String pc;
        private boolean isEmpty;
    }

}

テストベースクラス

package kurukuruz.sample.servlet.testbase;

import static org.mockito.Mockito.*;

import java.sql.Connection;
import java.sql.DriverManager;

import kurukuruz.sample.servlet.connection.ConnectionPool;

import org.junit.Before;
import org.junit.BeforeClass;
import org.powermock.api.mockito.PowerMockito;

public class ServletTestBase {

    protected static Connection Conn;

    @BeforeClass
    public static void setupBeforeClass() throws Exception {
        Class.forName("org.postgresql.Driver");
    }

    @Before
    public void setup() throws Exception {
        Conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/test", "user", "pass");

        PowerMockito.mockStatic(ConnectionPool.class);
        when(ConnectionPool.getConnection()).thenReturn(Conn);
    }

}

参考サイト