テストツール(三)——jMock 1.2
Jmockはオープンソースのツールで、junit、mock objectプロジェクトの上に構築され、非常に優れたテストツールです.
テストクラスはorgを継承する必要がある.jmock.MockObjectTestCase.
Jmockの用途はテストする方法とは関係のないクラスや本クラスの方法をシミュレートすることであるため,この点を理解するには,上記の手順が比較的理解しやすい.
xxクラスは私たちがmockを必要とするクラスであり、testBeanはテスト対象クラスであり、mockedMethodはテスト対象メソッド名である.
最後から2行目はxxを実行することを意味する.mockedMethodメソッドは、一度だけ実行され、パラメータはありません(パラメータがあり、パラメータが変わらない場合はeq、そうでない場合はisA、arrayContainingなど)、実行後に結果returnObjを返します.
次のtestBean.doTestMethodメソッドはxxを呼び出したに違いない.mockedMethodメソッド.これによりテストはtestBeanに集中できます.doTestMethod方法はTDD開発モデル(Test Directive development)に適している.
このコードには、次の点に注意してください.
1、このテストクラスはJMockのMockObjectTestCaseを継承している
2、private Mock userDAO = null;説明userDaoは仮想オブジェクトの準備をしています
3、setup()でuserDAO.classがMock()に転送された後、proxy()メソッドでUserDAOのプロキシクラスインスタンス(仮想オブジェクトインスタンス)を返し、userServiceに値を割り当てます.
4、このコードは長いですが、次のように理解できます.
1) userDAO.expects(once():userDAOのメソッドが1回実行されることを期待しています.このメソッドが実行されていないか、2回以上実行されている場合、テストは合格しません.
2)method("getUser"):この一度実行することを望む方法の名前はuserDAOである.getUser()
3)with(eq(1 L):getUser()メソッドを実行すると、入力されたパラメータ値が「1 L」であることを確認します.
4)will(returnValue):上記の条件が満たされた後、虚偽のオブジェクト、すなわち、前にインスタンス化されたfakeUserを返します.
全体的に、2行目の文を設定と、JMockはバックグラウンドで監視し、userDAOを確保する.getUser()は必須で、一度だけ実行され、パラメータ「1 L」はこのメソッドに正しく渡され、これらの条件が満たされるとfakeUserに戻ります.
3行目では、User user=userServicesとなります.getUser(1 L)は、賞品fakeUserを受け入れ、userオブジェクトに付与する奨励として、これらの条件をすべてトリガーします.次の4行目と5行目は、このuserオブジェクトをテストします.合格しないのはおかしいです. 5. 5行目expects(once()).method("saveUser").with(same(fakeUser))は特殊です.まず、with(same(fakeUser))は、次の文でuser.setName(「Mike」)は名前のプロパティを変更しただけで、fakeUserのインスタンス参照は変更されていないため、条件を満たすことができます.次に、その後はありません.ウィル(returnValue)は、userDAOのためだ.saveUser()は、オブジェクトまたは基本データ型を返す必要はありません.
また、userDAOを再度実行する.expects()の場合、JMockは監視条件をリセットします.私たちもuserDAOを通じてreset()は、モニタリング条件をクリアすることを明示的に示す.
以上のインスタンスコードとその説明から,JMockをうまく使う鍵は,まずモニタリング条件を設定し,対応するテスト文を書くことであることが分かった.モニタリング条件を設定した後、あるセグメントのコードブロックの実行が完了した場合、モニタリング条件が満たされていないか、expects()によって再び条件をリセットしていないか、reset()によってモニタリング条件を明示的にクリアしていない場合、テストは合格できません.
継承が必要ですorg.jmock.cglib.MockObjectTestCaseクラスは,同時にMockクラスを新規作成する際に変数名をパラメータとする必要がある.上のクラスをサービス2に変更します.その他は変更されません.
クラスのMockでは,代数パラメータの構築方法がある場合,パラメータとパラメータタイプをパラメータとして,それぞれ1つの配列にまとめる必要がある.mockメソッドに追加すればいいです.次のようになります.
インタフェースのシミュレーション
テストクラスはorgを継承する必要がある.jmock.MockObjectTestCase.
Mock tobeMock=new Mock(xx.class);
testBean.setXxx(tobeMock);
tobeMock.expects(once()).method("mockedMethod").withAnyArguments().will(returnValue(returnObj));
testBean.doTestMethod();
Jmockの用途はテストする方法とは関係のないクラスや本クラスの方法をシミュレートすることであるため,この点を理解するには,上記の手順が比較的理解しやすい.
xxクラスは私たちがmockを必要とするクラスであり、testBeanはテスト対象クラスであり、mockedMethodはテスト対象メソッド名である.
最後から2行目はxxを実行することを意味する.mockedMethodメソッドは、一度だけ実行され、パラメータはありません(パラメータがあり、パラメータが変わらない場合はeq、そうでない場合はisA、arrayContainingなど)、実行後に結果returnObjを返します.
次のtestBean.doTestMethodメソッドはxxを呼び出したに違いない.mockedMethodメソッド.これによりテストはtestBeanに集中できます.doTestMethod方法はTDD開発モデル(Test Directive development)に適している.
例
import com.sarkuya.model.User;
import junit.framework.*;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
public class UserServiceTest extends MockObjectTestCase {
private UserService userService = new UserServiceImpl();
private Mock userDAO = null;
public UserServiceTest(String testName) {
super(testName);
}
//
protected void setUp() throws Exception {
userDAO = new Mock(UserDAO.class);
userService.setUserDAO((UserDAO)userDAO.proxy());
}
protected void tearDown() throws Exception {
userDAO = null;
userService=null;
}
public static Test suite() {
TestSuite suite = new TestSuite(UserServiceTest.class);
return suite;
}
public void testGetUser() {
User fakeUser = new User("John");
userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(fakeUser));
// userDAO.expects(atLeastOnce()).method("getUser").with(eq(1L))
// .will( onConsecutiveCalls(
// returnValue(fakeUser),
// returnValue(20),
// throwException(new IOException("end of stream")) ) );
//
User user = userService.getUser(1L);
assertNotNull(user);
assertEquals("John", user.getName());
}
public void testSaveUser() {
User fakeUser = new User("John");
userDAO.expects(this.once()).method("getUser").with(eq(1L)).will(returnValue(fakeUser));
User user = userService.getUser(1L);
assertEquals("John", user.getName());
userDAO.expects(once()).method("saveUser").with(same(fakeUser));
user.setName("Mike");
userService.saveUser(user);
userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(user));
User modifiedUser = userService.getUser(1L);
assertEquals("Mike", user.getName());
}
}
このコードには、次の点に注意してください.
1、このテストクラスはJMockのMockObjectTestCaseを継承している
2、private Mock userDAO = null;説明userDaoは仮想オブジェクトの準備をしています
3、setup()でuserDAO.classがMock()に転送された後、proxy()メソッドでUserDAOのプロキシクラスインスタンス(仮想オブジェクトインスタンス)を返し、userServiceに値を割り当てます.
4、このコードは長いですが、次のように理解できます.
1) userDAO.expects(once():userDAOのメソッドが1回実行されることを期待しています.このメソッドが実行されていないか、2回以上実行されている場合、テストは合格しません.
2)method("getUser"):この一度実行することを望む方法の名前はuserDAOである.getUser()
3)with(eq(1 L):getUser()メソッドを実行すると、入力されたパラメータ値が「1 L」であることを確認します.
4)will(returnValue):上記の条件が満たされた後、虚偽のオブジェクト、すなわち、前にインスタンス化されたfakeUserを返します.
全体的に、2行目の文を設定と、JMockはバックグラウンドで監視し、userDAOを確保する.getUser()は必須で、一度だけ実行され、パラメータ「1 L」はこのメソッドに正しく渡され、これらの条件が満たされるとfakeUserに戻ります.
3行目では、User user=userServicesとなります.getUser(1 L)は、賞品fakeUserを受け入れ、userオブジェクトに付与する奨励として、これらの条件をすべてトリガーします.次の4行目と5行目は、このuserオブジェクトをテストします.合格しないのはおかしいです. 5. 5行目expects(once()).method("saveUser").with(same(fakeUser))は特殊です.まず、with(same(fakeUser))は、次の文でuser.setName(「Mike」)は名前のプロパティを変更しただけで、fakeUserのインスタンス参照は変更されていないため、条件を満たすことができます.次に、その後はありません.ウィル(returnValue)は、userDAOのためだ.saveUser()は、オブジェクトまたは基本データ型を返す必要はありません.
また、userDAOを再度実行する.expects()の場合、JMockは監視条件をリセットします.私たちもuserDAOを通じてreset()は、モニタリング条件をクリアすることを明示的に示す.
以上のインスタンスコードとその説明から,JMockをうまく使う鍵は,まずモニタリング条件を設定し,対応するテスト文を書くことであることが分かった.モニタリング条件を設定した後、あるセグメントのコードブロックの実行が完了した場合、モニタリング条件が満たされていないか、expects()によって再び条件をリセットしていないか、reset()によってモニタリング条件を明示的にクリアしていない場合、テストは合格できません.
非インタフェースのシミュレーション
継承が必要ですorg.jmock.cglib.MockObjectTestCaseクラスは,同時にMockクラスを新規作成する際に変数名をパラメータとする必要がある.上のクラスをサービス2に変更します.その他は変更されません.
public class Service2
{
private UserDAOImpl userDAO;
public void setUserDAO(UserDAOImpl userDAO) {
this.userDAO = userDAO;
}
public void saveUser(User user) throws Exception {
userDAO.saveUser(user);
}
public User getUser(long id)
{
return userDAO.getUser(id);
}
}
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jmock.Mock;
import org.jmock.cglib.MockObjectTestCase;
public class Service2Test extends MockObjectTestCase
{
private Service2 userService = new Service2();
private Mock userDAO = null;
public Service2Test(String testName)
{
super(testName);
}
protected void setUp() throws Exception
{
//
userDAO = mock(UserDAOImpl.class, "userDAO");
userService.setUserDAO((UserDAOImpl) userDAO.proxy());
}
protected void tearDown() throws Exception
{
}
public static Test suite()
{
TestSuite suite = new TestSuite(Service2Test.class);
return suite;
}
public void testGetUser()
{
User fakeUser = new User("John");
userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(fakeUser));
User user = userService.getUser(1L);
assertNotNull(user);
assertEquals("John", user.getName());
}
public void testSaveUser()
{
User fakeUser = new User("John");
userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(fakeUser));
User user = userService.getUser(1L);
assertEquals("John", user.getName());
userDAO.expects(once()).method("saveUser").with(same(fakeUser));
user.setName("Mike");
try {
userService.saveUser(user);
} catch (Exception e) {
e.printStackTrace();
}
userDAO.expects(once()).method("getUser").with(eq(1L)).will(returnValue(user));
User modifiedUser = userService.getUser(1L);
assertEquals("Mike", user.getName());
}
}
クラスのMockでは,代数パラメータの構築方法がある場合,パラメータとパラメータタイプをパラメータとして,それぞれ1つの配列にまとめる必要がある.mockメソッドに追加すればいいです.次のようになります.
Class [] pClass = {String.class, String.class};
String pass=...,name=...;
Object [] pObject = {pass,name};
userDAO = mock(UserDAOImpl.class, "userDAO",pClass,pObject);