Search on the blog

2014年2月28日金曜日

再帰呼び出しをスタックを使って書き換える

蟻本に以下のようなことが書かれています。

 関数の呼び出しはスタックで実現されています。したがって、再帰関数は再帰呼び出しの代わりにスタックを用いて書き直すこともできます。

実際に再帰呼び出しをスタックで書き直すとどんな感じになるか書いてみました。以下はn番目のフィボナッチ数を計算する処理です。
こうやって書いてみると、
  • DFS = スタック
  • BFS = キュー
という対比が分かって勉強になりました。

あまり綺麗に書けている気がしないので、こうやるともっと綺麗に書けるなどあれば教えてください。
#include <iostream>
#include <stack>

using namespace std;

struct frame {
    int x;
    int index;
    long long ret;

    frame(int x) : x(x), index(0) {
        ret = x <= 1 ? x : 0;
    }
};

long long fibonacci(int n) {
    stack<frame> stk;
    stk.push(frame(n));

    long long ret = -1;
    while (!stk.empty()) {
        frame &f = stk.top();
        
        if (f.x <= 1 || f.index == 2) {
            ret = f.ret;
            stk.pop();
            if (stk.empty())
                break;
            stk.top().ret += ret;
        } else {
            ++f.index;
            stk.push(frame(f.x - f.index));
        }
    }

    return ret;
}

int main(int argc, char **argv) {
    int n;
    cin >> n;

    cout << fibonacci(n) << endl;
 
    return 0;
}

2014年2月25日火曜日

telnetでポート接続を確認する


  telnetって遠隔操作のためのプロトコルだと思ってたけど、TCPポートの接続テストにも使えるみたいです。
 そういえば、昔telnetでHTTPサーバーに接続して「おーこれがステータスコードかー。」って確認して遊んだことがありました。コマンドラインから入力した文字をソケットの入力ストリームにそのまま入力して、ソケットからの出力をコマンドラインにそのまま出力してくれてるような感じだったので、echoサーバーを作って確認してみました。

 まずechoサーバー。今回の用途には特に不要ですが、練習のためマルチスレッド版を書きました。
package com.kenjih.echo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class EchoServer {

    private static class EchoProcessor extends Thread {
        private Socket socket = null;

        private EchoProcessor(Socket socket) {
            super(EchoProcessor.class.toString());
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                PrintWriter out = new PrintWriter(socket.getOutputStream(),
                        true);

                String line = null;
                while ((line = in.readLine()) != null) {
                    out.println(line);
                }

                System.out.printf("connection closed %s:%d\n",
                        socket.getInetAddress(), socket.getPort());
                socket.close();

            } catch (IOException e) {
                System.err.printf("error occurred in socket %s:%d\n",
                        socket.getInetAddress(), socket.getPort());
            }
        }
    }

    public static void main(String[] args) {
        if (args.length != 1 || !args[0].matches("^[0-9]+$")) {
            System.err.println("usege: java EchoServer <port number>");
            System.exit(1);
        }

        int port = Integer.valueOf(args[0]);
        boolean listening = true;

        try {
            ServerSocket serverSocket = new ServerSocket(port);
            while (listening) {
                Socket socket = serverSocket.accept();
                System.out.printf("connection opened %s:%d\n",
                        socket.getInetAddress(), socket.getPort());
                new EchoProcessor(socket).start();
            }
        } catch (IOException e) {
            System.err.println("Could not listen on port " + port);
        }
    }
}
でサーバーを起動。
$ java -cp bin com.kenjih.echo.EchoServer 12345

で別のコマンドラインからtelnet接続。ポイントはポート番号を指定しているところです。
$ telnet localhost 12345
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hogehoge
hogehoge
fugafuga
fugafuga
おー、なるほど。これは便利ですね。telnetはサーバーを書いた時のデバッグツールとして使えそうです。

2014年2月24日月曜日

神谷町/赤坂/六本木周辺のランチ

 最近ランチに凝っています。神谷町/赤坂/六本木あたりで安くて美味しいお店を探していこうかと思います。ローテーションリストに入りそうなお店をメモしておきます。

Bistro&Wine BATIC
赤坂ツインタワーの近くにあるフランス料理屋です。スープ、サラダ、肉、魚、デザートがついた「バティチランチ」が1,300円で食べることが出来ます。ライスお代わり無料です。

トスカーナ
神谷町の城山トラストタワーの中にあるイタリアンです。「日本一美味しいミートソース」という気になる名前のメニューがあります。もちもちとした生麺でした。ランチの予算は1,000円くらいです。

竜宮
城山トラストタワーの向かいの地下にある中華です。蟹あんかけチャーハンがおいしかったです。ランチの予算は1,000円くらいです。

モダン食堂 東京厨房
虎ノ門三丁目の交差点にあります。800円-1,000円くらいの定食が食べられます。ボリュームも結構あります。日替わりランチはなんと680円。

ケーキパパ
城山トラストタワーの向かいのビルの一階にあるカレー屋。ランチ予算は700-900円くらい。ライス普通盛りだと少し物足りなかったので、大盛(無料)にしてもらった方がいいと思います。

ディップマハル
溜池交差点付近にあるインド料理屋。1Fと2Fがある。カレーとナンが食べたいときにいいかも。ランチは800-1000円くらい。

若狭
福井の郷土料理屋。六本木通りの路地(インターコンチネンタルの向かい側あたり)に入っていくと店がある。魚系の定食が食べられる。予算は800-1000円くらい。弁当も売ってるっぽい。

魚六
若狭の近くにある魚屋さん。刺身定食や焼き魚定食が1000円。ご飯お代わり無料。味も◎。頻繁に通ってしまいそう。

TRATTORIA ESSE DUE
氷川坂周辺にあるイタリアン。パスタランチセット1000円。パンとサラダが食べ放題だけど、パンは冷たいし、サラダも新鮮ではなかった。パスタは美味しかった。

2014年2月23日日曜日

マルチキャストアドレスとは?

 マルチキャストアドレスが何なのか概念だけは知っていましたが、今日はじめてマルチキャストアドレスを使ってプログラムを書きました。

 UDPを使って、サーバーから230.0.0.1というグループに属するクライアントすべてにデータグラムを送信するというものです。

Broadcasting to Multiple Recipients

 最初見たときこの230.0.0.1というアドレスが何なのか分からなかったので調べてみました。

The multicast addresses are in the range 224.0.0.0 through 239.255.255.255.
ということらしいです[1]。

さらに、
The range of addresses between 224.0.0.0 and 224.0.0.255, inclusive,is reserved for the use of routing protocols and other low-leveltopology discovery or maintenance protocols, such as gateway discoveryand group membership reporting.

とある[1]ので、アプリケーションで自由に使えるマルチキャストアドレスは224.0.1.0 - 239.255.255.255ということだと思います。
と思いましたが、他にも予約されているアドレスがある[2]ようなので230.x.x.xあたりを使っておくと無難かなと思います。

ちなみに二進数で表記するとマルチキャストアドレスは以下のようになります。

1110xxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx   (xは任意)

Javaの場合、マルチキャストアドレスではないアドレスにジョインしようとすると以下の例外が出ました。
Exception in thread "main" java.net.SocketException: Not a multicast address
at java.net.MulticastSocket.joinGroup(MulticastSocket.java:306)
at com.kenjih.udp.MulticastClient.main(MulticastClient.java:12)


References
[1] IPv4 Multicast Address Space Registry
[2] Multicast address - Wikipedia, the free encyclopedia

2014年2月20日木曜日

JAXBとソケット通信でJavaBeansをリモートに送る


 JAXB(Java Architecture for XML Binding)というライブラリを使うとJavaBeans <-> XMLの変換が簡単に出来るみたいです。Java SE 6以降なら標準ライブラリに含まれています。これを使ってちょっと遊んでみました。

 XMLにシリアライズしたBeanをソケット通信でリモートサーバーに送って、リモートサーバー側では受け取ったXMLをBeanにデシリアライズして何か処理をしてみたら面白いかなーと思ってそれっぽいものを書いてみました。

 学生の実験レベルな感じですが、サーバーを起動した後、クライアント側で
~/workspace/sample/JAXB$ java -cp bin com.kenjih.socket.Client
taro
yamada
30
とすると、サーバー側で
Hello, I'm taro yamada, 30 years old!
と出力されて、おお!ってなりました。。

以下ソースコードです。
まず、Bean。
package com.kenjih.jaxb;

import java.io.Serializable;

public class Employee implements Serializable {
    private static final long serialVersionUID = 6128567005613141734L;

    private String firstName;
    private String lastName;
    private int age;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void greet() {
        System.out.printf("Hello, I'm %s %s, %d years old!\n",
                this.getFirstName(), this.getLastName(), this.getAge());
    }
}

次にサーバー。
package com.kenjih.socket;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.ServerSocket;
import java.net.Socket;

import javax.xml.bind.JAXB;

import com.kenjih.jaxb.Employee;

public class Server {
    public static void main(String argv[]) {
        try {
            ServerSocket serverSocket = new ServerSocket(55555);
            while (true) {
                Socket socket = serverSocket.accept();
                
                DataInputStream dis = new DataInputStream(socket.getInputStream());
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                for (int s; (s = dis.read(buffer)) != -1; ) {
                     baos.write(buffer, 0, s);
                }
                
                String xml = baos.toString();
                Employee emp = JAXB.unmarshal(new StringReader(xml), Employee.class);
                emp.greet();
            
                socket.close();
                Thread.sleep(1000);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

最後にクライアント。
package com.kenjih.socket;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.net.Socket;
import java.util.Scanner;

import javax.xml.bind.JAXB;

import com.kenjih.jaxb.Employee;

public class Client {
    public static void main(String argv[]) {
        try {
            Socket s = new Socket("localhost", 55555);

            DataOutputStream dos = new DataOutputStream(s.getOutputStream());

            Employee emp = new Employee();
            
            Scanner sc = new Scanner(System.in);
            String firstName = sc.next();
            String lastName = sc.next();
            int age = sc.nextInt();
            
            emp.setFirstName(firstName);
            emp.setLastName(lastName);
            emp.setAge(age);

            StringWriter stringWriter = new StringWriter();
            JAXB.marshal(emp, stringWriter);
            System.out.println(stringWriter);            
            dos.write(stringWriter.toString().getBytes());

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2014年2月15日土曜日

スタブとモックの違い

 スタブとモックの違いがようやく分かりました。一言で言うと、
スタブとはテスト対象の間接入力をテストシナリオに合わせて都合よく書き換えるためのもの。モックとはテスト対象の間接出力が正しいことを確認するためのもの。
です[1]。

間接入力、間接出力とはその名のとおりテスト対象の間接的な入力、出力のことです。例えば、サービスクラスをテストする場合を考えてみます。

boolean createService(Entity entity)

というメソッドをテストする場合、メソッドの入力はentity、出力はtrue/falseです。
直接的な入出力はこれだけですが、サービスクラスからDaoの処理を呼び出す場合、その処理結果が間接的にサービスクラスに入力されます。同様にサービスクラスはDaoクラスを呼び出すという間接的な出力処理を行います。


実際のテストコードを使ってスタブ、モックそれぞれの使い方を考えてみます。
以下のサービスクラスをテストする場合を考えます。
package com.kenjih.sample.service;

import java.sql.SQLException;
import java.util.Date;

import com.kenjih.sample.Dao.OrderDao;
import com.kenjih.sample.component.UserContext;
import com.kenjih.sample.entity.OrderEntity;
import com.kenjih.sample.exception.BussinessException;

public class OrderServiceImpl implements OrderService {

    OrderDao orderDao;

    UserContext userContext;
    
    public boolean addOrder(OrderEntity entity) {
        if (entity == null)
            throw new BussinessException("entity is null.");

        String userId = userContext.getLoginUser();
        if (userId == null)
            throw new BussinessException("user is not logged in.");
        
        entity.setOrderedBy(userId);
        entity.setOrderedAt(new Date());        

        boolean result = false;
        try {
            result = orderDao.create(entity);
        } catch (SQLException ex) {
            throw new BussinessException("database error occurred.", ex);
        } catch (Exception ex) {
            throw new BussinessException("unknown error occurred.", ex);
        }

        return result;
    }
}
上記のテスト対象をテストする場合どのようなコードを書けばいいか考えてみます。
まず、テスト対象のすべての文が網羅されるように条件を考えます。分岐条件が引数entityに加えて
  • UserContext#getLoginUser()
  • OrderDao#create()
からの間接入力に依存しているため、間接入力を都合のいいように書き換える必要がでてきます。このときに利用するのがスタブです。

次に、テスト対象の出力が正しいことを検証します。テスト対象の戻り値(またはスローされる例外)が正しいことを確認する他に、処理の内部で行われる間接的な出力が正しいことを確認する必要があります。例えば上の処理の場合、
  • ログインユーザーが取得できなかった場合は、OrderDao#create()を呼び出さない。
  • ログインユーザーが取得できた場合は、引数Entityと同じインスタンスを使ってOrderDao#create()を一度だけ呼び出す。
などを確認する必要があります。このように間接出力が正しいことを検証するために使用するのがモックです。

以下にMockitoを利用した場合のテストコードを載せておきます。
文法上@Mockを使っていますが、実際は、orderDao、userContextともにスタブかつモックの役割を果たしています。
when(oo).thenReturn(xx)、when(oo).thenThrow(xx)の部分ではスタブとして使い、verify(oo).xxx()の部分ではモックとして使っています。

package com.kenjih.sample.service;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.sql.SQLException;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import com.kenjih.sample.component.UserContext;
import com.kenjih.sample.entity.OrderEntity;
import com.kenjih.sample.exception.BussinessException;
import com.kenjih.sample.Dao.OrderDao;

@RunWith(MockitoJUnitRunner.class)
public class OrderServiceTest {

    @Mock
    private OrderDao orderDao;

    @Mock
    private UserContext userContext;

    @InjectMocks
    private OrderServiceImpl orderService;

    /*
     * 入力entityがnullの場合
     */
    @Test
    public void testUpdate_1() throws SQLException {
        try {
            orderService.addOrder(null);
            fail();
        } catch (BussinessException ex) {
            assertEquals("entity is null.", ex.getMessage());
            verify(userContext, never()).getLoginUser();
            verify(orderDao, never()).create((OrderEntity)anyObject());
        }
    }

    @Test
    /*
     * userContext.getLoginUser()からの間接入力がnullの場合
     */
    public void testUpdate_2() throws SQLException {
        when(userContext.getLoginUser()).thenReturn(null);

        try {
            orderService.addOrder(new OrderEntity());
            fail();
        } catch (BussinessException ex) {
            assertEquals("user is not logged in.", ex.getMessage());
            verify(userContext).getLoginUser();            
            verify(orderDao, never()).create((OrderEntity)anyObject());
        }
    }

    @Test
    /*
     * orderDao.create()からの間接入力がSQLExceptionの場合
     */
    public void testUpdate_3() throws SQLException {
        when(userContext.getLoginUser()).thenReturn("user001");
        when(orderDao.create((OrderEntity) anyObject())).thenThrow(
                new SQLException());

        try {
            orderService.addOrder(new OrderEntity());
            fail();
        } catch (BussinessException ex) {
            assertEquals("database error occurred.", ex.getMessage());
            verify(userContext).getLoginUser();            
            verify(orderDao).create((OrderEntity)anyObject());
        }
    }

    @Test
    /*
     * orderDao.create()からの間接入力がSQLException意外の例外の場合
     */
    public void testUpdate_4() throws SQLException {
        when(userContext.getLoginUser()).thenReturn("user001");
        when(orderDao.create((OrderEntity) anyObject())).thenThrow(
                new RuntimeException());

        try {
            orderService.addOrder(new OrderEntity());
            fail();
        } catch (BussinessException ex) {
            assertEquals("unknown error occurred.", ex.getMessage());
            verify(userContext).getLoginUser();            
            verify(orderDao).create((OrderEntity)anyObject());
        }
    }

    @Test
    /*
     * orderDao.create()からの間接入力がfalseの場合
     */
    public void testUpdate_5() throws SQLException {
        when(userContext.getLoginUser()).thenReturn("user001");
        when(orderDao.create((OrderEntity) anyObject())).thenReturn(false);

        OrderEntity entity = new OrderEntity();
        assertFalse(orderService.addOrder(entity));
        verify(userContext).getLoginUser();            
        verify(orderDao).create(entity);
    }

    @Test
    /*
     * orderDao.create()からの間接入力がtrueの場合
     */
    public void testUpdate_6() throws SQLException {
        when(userContext.getLoginUser()).thenReturn("user001");
        when(orderDao.create((OrderEntity) anyObject())).thenReturn(true);

        OrderEntity entity = new OrderEntity();
        assertTrue(orderService.addOrder(entity));
        verify(userContext).getLoginUser();            
        verify(orderDao).create(entity);
    }

}

References
[1] Test Double at XUnitPatterns.com

2014年2月14日金曜日

MockitoでUnitテスト効率化



 Mockitoというテストフレームワークがとても便利です。いわゆるモッキングフレームワークなのですが、SpringなどのDIコンテナを使って依存性を注入しているようなケースでもスタブ/モックを簡単に作ってくれて使いやすいです。

準備
Mavenを使って必要なライブラリをインストールします。pom.xmlに以下を記述してください。 直接関係はありませんが、サンプルでCommons Langも使っているためそれもdependenciesに含めています。
<dependencies>
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>1.9.0</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.0</version>
    </dependency>
</dependencies>
簡単な機能の使用例
Mockitoの機能を使ってみます。djUnitのVirtual Mock Objectsのようなことが出来ます。
package com.kenjih.mockito;

import java.util.LinkedList;
import java.util.List;

import org.junit.Test;

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;


public class Sample {
    @Test
    public void runTest1() {
        List mockedList = mock(List.class);

        mockedList.add("hoge");
        mockedList.clear();
        mockedList.add("fuga");
        mockedList.add("fuga");
        mockedList.add("fuga");

        // "hoge"を引数にしてaddメソッドは一度だけ呼ばれたか?
        verify(mockedList).add("hoge");
        
        // clearメソッドは一度だけ呼ばれたか?
        verify(mockedList).clear();
        
        // "fuga"を引数にしてaddメソッドはちょうど3回呼ばれたか?
        verify(mockedList, times(3)).add("fuga");
        
        // isEmptyメソッドは呼ばれていないか?
        verify(mockedList, never()).isEmpty();

    }
    
    @Test
    public void runTest2() {
        LinkedList mockedList = mock(LinkedList.class);

        // mockedList.get(0)が呼ばれたら必ず"first"を返すように設定。
        when(mockedList.get(0)).thenReturn("first");
        
        // mockedList.get(1)が呼ばれたらRuntimeExceptionをスローするように設定。
        when(mockedList.get(1)).thenThrow(new RuntimeException());

        assertEquals("first", mockedList.get(0));
        assertEquals("first", mockedList.get(0));
        
        try {
            mockedList.get(1);
            fail();
        } catch(RuntimeException e) {
            
        }
        
        // 値が設定されていない場合はnullを返す。
        assertNull(mockedList.get(2));
        
        // 任意の引数に対して、mockedList.getは"hoge"を返すように設定。
        when(mockedList.get(anyInt())).thenReturn("hoge");
        for (int i = 0; i < 10; i++)
            assertEquals("hoge", mockedList.get(i));
    }
}
Mockitoを用いたUnit Testの例
簡単な使い方を紹介したところで、もう少し実用的な例を考えます。 例としてサービスクラスの単体テストを考えます。サービスクラスはDAOを持っていて、DAOの部分をモック化してテストを行います。以下の例では、DAOはコンストラクタ/セッターでセットされる想定になっていますが、SpringなどのDIコンテナからDAOをインジェクションしている場合にも同様の方法でモックを使うことが出来ます。

まず、テスト対象のサービスクラスです。updateメソッドをテストすることを考えてみてください。(サンプルなので処理はかなり適当に書いてます)
package com.kenjih.mockito;

import java.sql.SQLException;

public class Service {

    private Dao dao;   
    
    public boolean update(Entity entity) {
        if (entity == null) {
            return false;
        }
        
        boolean ret = false;
        try {
            ret = dao.update(entity);
        } catch (SQLException e) {
            throw new BussinessException("Database access error occurred.", e);            
        } catch (RuntimeException e) {
            throw new BussinessException("Unknown error occurred.");
        }
        
        if (!ret) {
            throw new BussinessException("data was not updated.");
        }
        
        return true;
    }
}

サービスクラスから参照されているクラスの定義は以下のとおりです。
package com.kenjih.mockito;

import java.sql.SQLException;

public interface Dao {
    boolean create(Entity entity) throws SQLException;
    Entity read(int id) throws SQLException;
    boolean update(Entity entity) throws SQLException;
    boolean delete(Entity entity) throws SQLException;
}
package com.kenjih.mockito;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Entity {
    private String name;

    public Entity() {}

    public Entity(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(name).toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Entity)) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        Entity rhs = (Entity) obj;
        return new EqualsBuilder().append(name, rhs.name).isEquals();
    }
}
package com.kenjih.mockito;

public class BussinessException extends RuntimeException {

    private static final long serialVersionUID = 2986073923681825950L;

    public BussinessException() {  
        super();  
    }  
  
    public BussinessException(String message) {  
        super(message);  
    }  
  
    public BussinessException(String message, Throwable throwable) {  
        super(message, throwable);  
    }  
  
    public BussinessException(Throwable throwable) {  
        super(throwable);  
    }  
}

そして以下がテスト実行クラスです。@MockでmockedDaoがモックになっているところと、@InjectMocksでserviceにモック化されたオブジェクトが注入されているところがポイントです。
また、@Beforeが付与されたメソッドでモックの挙動を定義しています。mockedDao#update()メソッドを呼んだ場合の戻り値を、引数ごとに指定しています(どの引数パターンにマッチするかの判定には引数Entityのequalsメソッドが使われます)。
package com.kenjih.mockito;

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

import java.sql.SQLException;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class TestService {
    
    @Mock
    private Dao mockedDao;
    
    @InjectMocks
    private Service service;   // Mockオブジェクト注入
    
    @Rule
    public ExpectedException exception = ExpectedException.none();

    @Before
    public void init() throws SQLException {
        // mockedDaoの振る舞いを設定する。
        when(mockedDao.update(new Entity("DB_ERR"))).thenThrow(new SQLException());
        when(mockedDao.update(new Entity("UNKNOWN_ERR"))).thenThrow(new RuntimeException());
        when(mockedDao.update(new Entity("FALSE"))).thenReturn(false);
        when(mockedDao.update(new Entity("SUCCESS"))).thenReturn(true);    
    }
    
    @Test 
    public void testUpdate_1() {
        assertEquals(false, service.update(null));
    }
    
    @Test
    public void testUpdate_2() {
        exception.expect(BussinessException.class);
        exception.expectMessage("Database access error occurred.");
        service.update(new Entity("DB_ERR"));
    }
    
    @Test
    public void testUpdate_3() {
        exception.expect(BussinessException.class);
        exception.expectMessage("Unknown error occurred.");
        service.update(new Entity("UNKNOWN_ERR"));        
    }
    
    @Test
    public void testUpdate_4() {
        assertTrue(service.update(new Entity("SUCCESS")));    
    }
    
}