CppUnit 을 이용한 MFC 에서의 GuiTesting (시도중. 결과는?) === Dialog Based 에서의 테스트 === Dialog Based 의 경우 Modal Dialog 를 이용하게 된다. 이 경우 Dialog 내에서만 메세지루프가 작동하게 되므로, DoModal 함수로 다이얼로그를 띄운 이후의 코드는 해당 Dialog 가 닫히기 전까지는 실행되지 않는다. 고로, CppUnit 에서의 fixture 를 미리 구성하여 쓸 수 없다. 그래서, 테스트를 시도할때 Modaless Dialog 로 만들고 실험을 하였다. http://zeropage.org/pub/GuiTesting/GuiTest1.gif 원하는 작동 모습은 이렇다. 1. Editbox 에 아무 글을 넣고 2. Add 버튼을 누르면 3. List box 에 Editbox 에 쓴 글이 순서대로 처음부터 채워지고 4. List box 에서의 커서는 채워진 글에 위치한다. 5. List box 에 값이 채워지고 난 뒤, Editbox 의 글은 지워진다. === 1. GUI Runner Setting === 이는 App 클래스의 InitInstance 함수에서 해준다. {{{~cpp #include "stdafx.h" #include "GuiTestingOne.h" #include "GuiTestingOneDlg.h" #include "cppunit\ui\mfc\TestRunner.h" #include "GuiTestCase.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif BEGIN_MESSAGE_MAP(CGuiTestingOneApp, CWinApp) //{{AFX_MSG_MAP(CGuiTestingOneApp) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG ON_COMMAND(ID_HELP, CWinApp::OnHelp) END_MESSAGE_MAP() CGuiTestingOneApp::CGuiTestingOneApp() { } CGuiTestingOneApp theApp; BOOL CGuiTestingOneApp::InitInstance() { AfxEnableControlContainer(); CppUnit::MfcUi::TestRunner runner; runner.addTest (GuiTestCase::suite()); runner.run(); /* --- Test Runner 만 실행되도록, 다이얼로그 띄우는 부분을 일단 막아둔다. 마지막에 실행할때 이 부분의 주석처리 된 부분을 풀어주면 된다. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif CGuiTestingOneDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } */ return FALSE; } }}} === 2. Test Case 의 작성 === ==== 1. 연습 ==== 일단, 제대로 작동하는지 알아보기 위해 연습겸 m_bFlag 변수를 만들어서 테스트를 했다. || 테스트 || 통과시 예상되는 결과 || || test1One || 연습겸 Assert Equals. 10 == 10 || || test2GuiOne || 버튼이 눌러졌을 경우에 CGuiTestingOneDlg::m_bFlag 가 true 상태가 된다. || {{{~cpp #include #include #include "stdafx.h" // resource, mfc 를 이용할 수 있다. #include "GuiTestingOneDlg.h" // import GuiTestingOneDlg class GuiTestCase : public CppUnit::TestCase { CPPUNIT_TEST_SUITE(GuiTestCase); CPPUNIT_TEST ( test1One ); CPPUNIT_TEST ( test2GuiOne ); CPPUNIT_TEST ( test3ListAdd ); CPPUNIT_TEST_SUITE_END(); public: CGuiTestingOneDlg* pDlg; void setUp () { pDlg = new CGuiTestingOneDlg(); pDlg->Create(IDD_GUITESTINGONE_DIALOG); } void tearDown () { delete pDlg; } public: void test1One () { CPPUNIT_ASSERT_EQUAL (10, 10); } void test2GuiOne () { pDlg->OnButtonadd(); CPPUNIT_ASSERT_EQUAL (true, pDlg->m_bFlag); } }; }}} 코드 추가 {{{~cpp void CGuiTestingOneDlg::OnButtonadd() { // TODO: Add your control notification handler code here m_bFlag = true; } }}} ==== 2. 텍스트 추가 ==== || 테스트 || 통과시 예상되는 결과 || || test1One || 연습겸 Assert Equals. 10 == 10 || || test2GuiOne || 버튼이 눌러졌을 경우에 CGuiTestingOneDlg::m_bFlag 가 true 상태가 된다. || || test3ListAdd || Editbox 에 "Testing..." 을 셋팅. 버튼을 눌렀을 때 Listbox 의 item 갯수가 1개임을 확인 || || . || Listbox 의 첫번째 item 의 스트링이 "Testing..." 임을 확인 || {{{~cpp void test3ListAdd () { pDlg->m_ctlEdit.SetWindowText("Testing..."); pDlg->OnButtonadd(); CPPUNIT_ASSERT_EQUAL (1, pDlg->m_ctlList.GetCount()); CString str; pDlg->m_ctlList.GetText(0, str); CPPUNIT_ASSERT ( isSameString(str, "Testing...")); } bool isSameString (CString& str1, PSTR str2) { return str1.Compare(str2) == 0; } }; }}} 코드 추가 {{{~cpp void CGuiTestingOneDlg::OnButtonadd() { // TODO: Add your control notification handler code here m_bFlag = true; CString str; m_ctlEdit.GetWindowText(str); m_ctlList.AddString(str); } }}} ==== 3. more... ==== || 테스트 || 통과시 예상되는 결과 || || test1One || 연습겸 Assert Equals. 10 == 10 || || test2GuiOne || 버튼이 눌러졌을 경우에 CGuiTestingOneDlg::m_bFlag 가 true 상태가 된다. || || test3ListAdd || Editbox 에 "Testing..." 을 셋팅. 버튼을 눌렀을 때 Listbox 의 item 갯수가 1개임을 확인 || || . || Listbox 의 첫번째 item 의 문자열이 "Testing..." 임을 확인 || || test4ListAddMore || test3 에 추가된 형태. Editbox 에 다시 "Testing2..." 를 셋팅하고, 버튼을 눌렀을 때 Listbox 의 item 갯수가 2개임을 확인 || || . || Listbox 의 두번째 item 의 문자열이 "Testing2..." 임을 확인 || {{{~cpp void test4ListAddMore () { test3ListAdd(); CString str; pDlg->m_ctlEdit.SetWindowText("Testing2..."); pDlg->OnButtonadd(); CPPUNIT_ASSERT_EQUAL (2, pDlg->m_ctlList.GetCount()); pDlg->m_ctlList.GetText(1, str); CPPUNIT_ASSERT ( isSameString(str, "Testing2...")); } }}} ==== 4. 'List box 에서의 커서는 채워진 글에 위치한다' 에 대한 테스트 ==== || 테스트 || 통과시 예상되는 결과 || || test1One || 연습겸 Assert Equals. 10 == 10 || || test2GuiOne || 버튼이 눌러졌을 경우에 CGuiTestingOneDlg::m_bFlag 가 true 상태가 된다. || || test3ListAdd || Editbox 에 "Testing..." 을 셋팅. 버튼을 눌렀을 때 Listbox 의 item 갯수가 1개임을 확인 || || . || Listbox 의 첫번째 item 의 문자열이 "Testing..." 임을 확인 || || test4ListAddMore || test3 에 추가된 형태. Editbox 에 다시 "Testing2..." 를 셋팅하고, 버튼을 눌렀을 때 Listbox 의 item 갯수가 2개임을 확인 || || . || Listbox 의 두번째 item 의 문자열이 "Testing2..." 임을 확인 || || test5ListCursorOne || test3 진행시 선택된 Item 이 0 번째 임을 확인 || || test6ListCursorTwo || test4 진행시 선택된 Item 이 1 번째 임을 확인 || {{{~cpp void test5ListCursorOne () { test3ListAdd(); CPPUNIT_ASSERT_EQUAL(0, pDlg->m_ctlList.GetCurSel()); } void test6ListCursorTwo () { test4ListAddMore(); CPPUNIT_ASSERT_EQUAL(1, pDlg->m_ctlList.GetCurSel()); } }}} http://zeropage.org/pub/GuiTesting/GuiTestFail.gif 코드 추가 {{{~cpp void CGuiTestingOneDlg::OnButtonadd() { // TODO: Add your control notification handler code here CString str; m_ctlEdit.GetWindowText(str); m_ctlList.AddString(str); m_ctlList.SetCurSel(m_ctlList.GetCount()-1); m_bFlag = true; } }}} http://zeropage.org/pub/GuiTesting/GuiTestOk.gif ==== 5. edit box 의 내용이 데이터 추가후 초기화 되는지 확인 ==== || 테스트 || 통과시 예상되는 결과 || || test1One || 연습겸 Assert Equals. 10 == 10 || || test2GuiOne || 버튼이 눌러졌을 경우에 CGuiTestingOneDlg::m_bFlag 가 true 상태가 된다. || || test3ListAdd || Editbox 에 "Testing..." 을 셋팅. 버튼을 눌렀을 때 Listbox 의 item 갯수가 1개임을 확인 || || . || Listbox 의 첫번째 item 의 문자열이 "Testing..." 임을 확인 || || test4ListAddMore || test3 에 추가된 형태. Editbox 에 다시 "Testing2..." 를 셋팅하고, 버튼을 눌렀을 때 Listbox 의 item 갯수가 2개임을 확인 || || . || Listbox 의 두번째 item 의 문자열이 "Testing2..." 임을 확인 || || test5ListCursorOne || test3 진행시 선택된 Item 이 0 번째 임을 확인 || || test6ListCursorTwo || test4 진행시 선택된 Item 이 1 번째 임을 확인 || || test7EmptyEditbox || test3 진행시 Editbox 의 스트링이 비었는지 확인 || {{{~cpp void test7EmptyEditbox () { test3ListAdd(); CString str; pDlg->m_ctlEdit.GetWindowText(str); CPPUNIT_ASSERT (str.IsEmpty()); } }}} 코드 추가 {{{~cpp void CGuiTestingOneDlg::OnButtonadd() { // TODO: Add your control notification handler code here CString str; m_ctlEdit.GetWindowText(str); m_ctlList.AddString(str); m_ctlList.SetCurSel(m_ctlList.GetCount()-1); m_ctlEdit.SetWindowText(""); m_bFlag = true; } }}} 여기까지로 생각해놓은 테스트들이 전부 완료. 앞에 InitInstance 에 써 넣은 주석을 풀고, 실제로 실행해보자. {{{~cpp BOOL CGuiTestingOneApp::InitInstance() { AfxEnableControlContainer(); CppUnit::MfcUi::TestRunner runner; runner.addTest (GuiTestCase::suite()); runner.run(); #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif CGuiTestingOneDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } return FALSE; } }}} http://zeropage.org/pub/GuiTesting/result.gif === 문제점 === * 모달리스 다이얼로그인 관계로, 테스트를 run 으로 실행할 때 마다 Dialog 가 켜졌다 꺼졌다 한다. 이에 따른 속도의 지연의 문제. -> CDialog::ShowWindow(SH_HIDE); 로 해결 가능 ---- ["GuiTesting"]