【ログ】Vuetify追加後にtsconfig.jsonを修正する
※この記事はQrunchログからの移行記事です。
vue add vuetify
実行時に追加されるsrc/plugin/vuetify.ts
のimport宣言部分は以下のようになっている。
import Vuetify from 'vuetify/lib';
この部分について以下のようなコンパイルエラーが発生する。
モジュール 'vuetify/lib' の宣言ファイルが見つかりませんでした。(中略) Try
npm install @types/vuetify
if it exists or add a new declaration (.d.ts) file containingdeclare module 'vuetify/lib';
tsconfig.json
のコンパイラオプションにvuetify
を追加する。
{ "compilerOptions": { ... "types": [ - "webpack-env" + "webpack-env", + "vuetify" ], ... }, ... }
参考
JsRenderの基本的な使い方
6/23追記:Qiitaに転載しました。これからはQiitaを中心に投稿する予定です。 qiita.com 6/23追記ここまで
はじめに
htmlのテンプレートエンジンとしてjQuery Templatesを使用していたが、JSPでは使えなかった。 回避策を紹介しているサイトもあったが、そもそも現在はjQuery Templatesの開発がストップしているということで、後継ライブラリであるJsRenderに切り替えてみた。
導入
公式のサンプルに従ってWebから直接ロード。 jQuery非依存だがjQueryのプラグインとしても動作するので今回はjQueryと一緒に使う。
<script src="//code.jquery.com/jquery-1.12.4.js"></script> <script src="//www.jsviews.com/download/jsrender.js"></script>
使用方法
基礎
html側に<script type="text/x-jsrender>...</script>
内に定義したテンプレートとテンプレートを挿入する親要素を記述する。
なお、変数をバインドする部分は{{>変数名}}
と記述する。
<ul id="ul1"></ul><!-- 格納先 --> <script id="tmpl1" type="text/x-jsrender"> <!-- テンプレート --> <li>{{>id}} - {{>name}}</li> </script>
JavaScript側では 1. テンプレートのロードする
var $tmpl1 = $.templates("#tmpl1"); // -> JsRenderのインスタンス生成
または
var $tmpl1 = $("#tmpl1"); // -> jQueryのインスタンス生成
- データをバインドしたhtml部品の生成する(上記どちらのインスタンスでも同じ記述になる)
var data1 = {id:"001", name:"hoge"}; var dataHtml = $tmpl1.render(data1); // -> html部品(文字列)の生成
- DOMへ追加(以下どちらもjQueryの機能を利用)
$("#ul1").html(dataHtml); // -> #ul1の内容をdataHtmlに差し替え
または
$("#ul1").append(dataHtml); // -> #ul1の末尾にdataHtmlを追加
各関数で何が返却されるのかを確認するために細かく分けたが、再利用する必要がなければ以下のように1行で記述すればよい。
$("#ul1").append($("#tmpl1").render(data1));
⇒表示
基本的な使用例
公式のAPIドキュメントからいくつか抜粋する。
* オブジェクト配列データへのテンプレート適用
「基礎」の項では単独のオブジェクトをテンプレートに適用したが、1データ分のテンプレートに対してオブジェクト配列を投入した場合は自動でイテレーションされる。
また、変数の代わりに#index
を指定すると配列のインデックスが取得できる。
<ul id="ul2"></ul> <script id="tmpl2" type="text/x-jsrender"> <li>[{{>#index}}]:{{>id}}/{{>name}}</li> </script>
var data2 = [ {id:"001", name:"hoge"}, {id:"002", name:"foo"}, {id:"003", name:"bar"}, ]; $("#ul2").append($("#tmpl2").render(data2));
⇒表示
- 文字列配列データへのテンプレート適用
文字列配列の場合は変数として#data
を指定することで取得できる。
<ul id="ul3"></ul> <script id="tmpl3" type="text/x-jsrender"> <li>[{{>#index}}] - {{>#data}}</li> </script>
var data3 = ["one", "two", "three"]; $("#ul3").append($("#tmpl3").render(data3));
⇒表示
- テンプレート内でのイテレーション
テンプレート内でイテレーションする場合は
{{for 配列}}...{{/for}}
という構文を使用する。
変数や#index
、#data
はすべてイテレーション中のオブジェクトでの値になる。
(以下の例で3行目の{{>id}}
と6行目の{{>id}}
とでバインドされる値が異なることに注意)
<div id="div4"></div> <script id="tmpl4" type="text/x-jsrender"> <div>{{>id}}</div> <ol> {{for ary1}} <li>[{{>#index}}]:{{>id}}/{{>name}}</li> {{/for}} </ol> <ol> {{for ary2}} <li>[{{>#index}}] - {{>#data}}</li> {{/for}} </ol> </script>
⇒表示
- テンプレート内での条件分岐
テンプレート内で条件分岐を入れる場合は
{{if 条件}}...{{else 条件}}...{{else}}...{{/if}}
という構文を使用する。(「elseif」ではないので注意)
下記例の通り、条件には簡単な計算や比較演算を入れることも可能。
<ul id="ul5"></ul> <script id="tmpl5" type="text/x-jsrender"> <li> {{>#data}} : {{if #data % 3 == 0}} 3x {{else #data % 3 == 1}} 3x+1 {{else}} 3x+2 {{/if}} </li> </script>
var data5 = [19, 86, 12, 25]; $("#ul5").append($("#tmpl5").render(data5));
⇒表示
- htmlタグを適用するバインドとエスケープするバインド
これまでの例ではすべて変数のバインドに{{>変数}}
という記述をしてきたが{{:変数}}
という記述も可能である。{{>変数}}
: 変数の値をすべて文字列としてバインドする{{:変数}}
: 変数の値をhtml部品としてバインドする
<ul id="ul6"></ul> <script id="tmpl6_1" type="text/x-jsrender"> <li>{{>id}} - {{>name}}</li> </script> <script id="tmpl6_2" type="text/x-jsrender"> <li>{{:id}} - {{:name}}</li> </script>
var data6 = {id:"<strong>001</strong>", name:"<del>hoge</del>foo"}; $("#ul6").append($("#tmpl6_1").render(data6)); $("#ul6").append($("#tmpl6_2").render(data6));
⇒表示
参考サイト
JavaとExcelの有効桁数の違いとPOIでの取り込み
概要
JavaとExcelとで実数(浮動小数点)の有効桁数が異なる。
Excel内で計算式が適用されているセルをPOIで取り込むとJavaの有効桁数で再計算されるため(?)誤差が生じる。
値によっては人間が見える桁で差が生じてしまうので注意が必要。
※POIのソースを検証したわけではないので原因は推測
検証
Excelでの結果
A1セルはB列の合計値を小数点以下2桁目まで表示したもの、A2セルもB列の合計値。
ここからExcelでは情報落ちにより「厳密に1.115」と判断され、四捨五入の結果「1.12」が表示されていることがわかる。
Javaコード
public static void main(String[] args) throws EncryptedDocumentException, InvalidFormatException, FileNotFoundException, IOException{ Workbook wb = WorkbookFactory.create(new FileInputStream("data/input2.xlsx")); Sheet sheet = wb.getSheet("Sheet1"); double v = sheet.getRow(0).getCell(0).getNumericCellValue(); // A1セルを取得 System.out.println(v); BigDecimal bd = new BigDecimal(String.valueOf(v)); System.out.println(bd); System.out.println(bd.setScale(2, BigDecimal.ROUND_HALF_UP)); }
Java実行結果
1.1149999999999989 1.1149999999999989 1.11
-1e-15の加算が反映されて「1.11499...」と判断されている。そのため四捨五入の結果は「1.11」になる。
Mockitoのspyと例外(解決編)
概要
spy()
で作成したインスタンスに対して、本来例外が発生するパターンでwhen().thenReturn()
を用いてモックを定義しようとすると本来の例外が発生してしまいテストができない。
これを回避するためにはdoReturn()
を使えばよい。
検証
環境
ソースコード
前回と同じTarget
クラスを使用
テストコード
package kurukuruz.test.mock; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.Test; import org.mockito.Mockito; public class TargetTest2 { // Mockito.when実行時に例外が発生するパターン @Test(expected=IllegalStateException.class) public void Mockito_spy_thenReturn() { Target t = Mockito.spy(Target.class); Mockito.when(t.method1("hoge")).thenReturn("mock"); t.method1("hoge"); } // 意図通りにモック化するパターン @Test public void Mockito_spy_doReturn1() { Target t = Mockito.spy(Target.class); Mockito.doReturn("mock").when(t).method1("hoge"); String actual = t.method1("hoge"); assertThat(actual, is("mock")); } // spy対象外の引数なので実コードを実行し例外発生 @Test(expected=IllegalStateException.class) public void Mockito_spy_doReturn2() { Target t = Mockito.spy(Target.class); Mockito.doReturn("mock").when(t).method1("hoge"); t.method1("bar"); } }
参考サイト
Mockitoのspyと例外
現象
spy使ってたら例外が出た。
例外のスタックトレースを見ると、when()が実行されるタイミングで実コードが実行されて、発生した例外が持ち出されてくるようだ。
mockを使った場合はこの現象は発生しない。
検証
ソースコード
package kurukuruz.test.mock; public class Target { public String method1(String arg0) { throw new IllegalStateException("未実装!"); } public static String smethod(String arg0) { throw new IllegalStateException("未実装!"); } }
テストコード
package kurukuruz.test.mock; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest({Target.class}) public class TargetTest { @Test public void Mockito_mock() { System.out.println("---Mockito_mock---"); Target t = Mockito.mock(Target.class); Mockito.when(t.method1("hoge")).thenReturn("mock"); System.out.println(t.method1("hoge")); System.out.println(t.method1("foo")); } @Test public void Mockito_spy() { System.out.println("---Mockito_spy---"); Target t = Mockito.spy(Target.class); Mockito.when(t.method1("hoge")).thenReturn("mock"); System.out.println(t.method1("hoge")); System.out.println(t.method1("foo")); } @Test public void PowerMockito_mock() throws Exception { System.out.println("---PowerMockito_mock---"); Target t = PowerMockito.mock(Target.class); PowerMockito.when(t, "method1", "hoge").thenReturn("mock"); System.out.println(t.method1("hoge")); System.out.println(t.method1("foo")); } @Test public void PowerMockito_spy() throws Exception { System.out.println("---PowerMockito_spy---"); Target t = PowerMockito.spy(new Target()); PowerMockito.when(t, "method1", "hoge").thenReturn("mock"); System.out.println(t.method1("hoge")); System.out.println(t.method1("foo")); } @Test public void PowerMockito_mockStatic() { System.out.println("---PowerMockito_mockStatic---"); PowerMockito.mockStatic(Target.class); Mockito.when(Target.smethod("hoge")).thenReturn("mock"); System.out.println(Target.smethod("hoge")); System.out.println(Target.smethod("foo")); } }
実行結果
---PowerMockito_mock--- mock null ---PowerMockito_mockStatic--- mock null ---Mockito_spy--- ---Mockito_mock--- mock null ---PowerMockito_spy---
↓エラーが発生したケースのスタックトレース
Mockito+PowerMockで不可視メソッドをspy
目的
privateメソッドやパッケージ違いの親クラスのprotectedメソッドのようにテストコードから不可視なメソッドにspyを適用したい。
方法
PowerMockito.whenを使う。
Target target = PowerMockito.spy(new Target()); PowerMockito.when(target, "invisibleMethod", "hoge").thenReturn("mock-string");
(参考:Mockitoのspy)
Target target = Mockito.spy(new Target()); Mockito.when(target.method("hoge")).thenReturn("mock-string");
検証
いろんな不可視パターンで試してみる
ソースコード
テスト対象クラス
package kurukuruz.test.mock; import kurukuruz.test.mock.base.Parent; public class Target extends Parent { public String executeOwnMethod(){ return "own method return: " + private1(); } private String private1() { return "own"; } public String executeParent1() { return "method1 return: " + method1(); } public String executeParent2() { return "method2 return: " + method2(); } public String executeParent3() { return "method3 return: " + method3(); } public String executeParent4(String hoge) { return "method4 return: " + method4(hoge); } public String executeParent5(Dao dao) throws Exception { return "method5 return: " + method5(dao); } }
親クラス
package kurukuruz.test.mock.base; import lombok.Getter; import lombok.Setter; public class Parent { /** publicメソッド */ public String method1() { return "method1"; } /** protectedメソッド */ protected String method2() { return "method2"; } /** protected finalメソッド */ protected final String method3() { return "method3"; } /** 引数あり(文字列) */ protected final String method4(String hoge) { return hoge; } /** 引数が任意のオブジェクト */ protected final String method5(Dao dao) throws Exception { if(dao.getName() == null) { throw new Exception("name is null!"); } return dao.getName(); } @Setter @Getter public static class Dao { private String name; } }
テストコード
package kurukuruz.test.mock; import kurukuruz.test.mock.base.Parent.Dao; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(Enclosed.class) public class TargetTest { public static class そのまま実行 { @BeforeClass public static void setupBeforeClass() { System.out.println("---そのまま実行---"); } @Test public void テスト0() throws Exception{ Target t = new Target(); System.out.println(t.executeOwnMethod()); } @Test public void テスト1() throws Exception{ Target t = new Target(); System.out.println(t.executeParent1()); } @Test public void テスト2() throws Exception{ Target t = new Target(); System.out.println(t.executeParent2()); } @Test public void テスト3() throws Exception{ Target t = new Target(); System.out.println(t.executeParent3()); } @Test public void テスト4() throws Exception{ Target t = new Target(); System.out.println(t.executeParent4("hoge")); } @Test public void テスト5() throws Exception{ Target t = new Target(); Dao param1 = new Dao(); param1.setName("foo"); System.out.println(t.executeParent5(param1)); } } @RunWith(PowerMockRunner.class) @PrepareForTest({Target.class}) public static class モック実行 { @BeforeClass public static void setupBeforeClass() { System.out.println("---モック実行---"); } @Test public void テスト0() throws Exception{ Target t2 = PowerMockito.spy(new Target()); PowerMockito.when(t2, "private1").thenReturn("mock0"); System.out.println(t2.executeOwnMethod()); } @Test public void テスト1() throws Exception { Target t2 = PowerMockito.spy(new Target()); PowerMockito.when(t2, "method1").thenReturn("mock1"); System.out.println(t2.executeParent1()); } @Test public void テスト2() throws Exception { Target t2 = PowerMockito.spy(new Target()); PowerMockito.when(t2, "method2").thenReturn("mock2"); System.out.println(t2.executeParent2()); } @Test public void テスト3() throws Exception { Target t2 = PowerMockito.spy(new Target()); PowerMockito.when(t2, "method3").thenReturn("mock3"); System.out.println(t2.executeParent3()); } @Test public void テスト4() throws Exception { Target t2 = PowerMockito.spy(new Target()); PowerMockito.when(t2, "method4", "hoge").thenReturn("mock4"); System.out.println(t2.executeParent4("hoge")); System.out.println(t2.executeParent4("foo")); } @Test public void テスト5() throws Exception { Target t2 = PowerMockito.spy(new Target()); Dao dao = new Dao(); dao.setName("bar"); PowerMockito.when(t2, "method5", dao).thenReturn("mock5"); System.out.println(t2.executeParent5(dao)); } } }
実行結果
---そのまま実行--- own method return own method1 return method1 method2 return method2 method3 return method3 method4 return hoge method5 return foo ---モック実行--- method4 return mock4 method4 return foo method1 return mock1 own method return mock0 method2 return mock2 method3 return mock3 method5 return mock5
参考サイト
Servletクラスのテスト
目的
JSONを返却するServletクラスの単体テストがしたい。
概要
- GETメソッドのサーブレット
- doGetをたたく
- 引数にはMockHttpServletRequest, MockHttpServletResponseを利用
- Connectionはデータソースを利用
- PowerMockでモック
- JUnitのTheoryも併用
- PowerMockでモック
検証プログラム
概要
- 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); } }