2010년 7월 31일 토요일

[VS 2010] Visual Studio 2010 Tools - To improve code quality

원문은 Visual Studio 2010 Tools - To improve code quality 입니다.










Visual Studio 2010 Tools - To improve code quality











VS 2010 Tool을 사용하여 코드의 질을 향상시킬 수 있다. 이때 사용하는 Tool은 다음과 같다.





Unit Testing 


    코드 조각이나 기능들을 테스트하기 위하여 코드 조각을 작성하는 것을 말한다.





Code Coverage


    프로그램 소스내 특정 메소드가 실제 호출되서 사용되고 있는지, 그리고 사용된다면 빈도는 어느정도 인지, 또한 메소드내에 if문과 같은 조건식이 실제로 처리되고 있는지 처리된다면 빈도는 어느정도 인지 정보를 말한다. 음... 어렵네.. 자세한 정보는 다음 링크를 참조.


    cf) Code Coverage






● Test Impact Analysis





위 도구들의 VS 2010 각 에디션 별 지원 현황










데모 프로젝트를 만들어 각각을 테스트 해보기로 한다.





Step 1. Create Class Library





테스트할 클래스 라이브러리를 먼저 생성해 주자.





Class Library Name : MathLibrary


Class Name : CalculateBasic


Method : AddNumbers, SubstrctNumbers, MultiplyNumbers and DivideNumbers as shown below










Step2. Create Unit Test





 소스 코드서 마우스를 가져간 다음 마우스 오른쪽 버튼을 클릭한다.


팝업메뉴에서 "Create Unit Test..." 를 선택한다.













Create Unit Tests 윈도우에서 모든 메소드(생성자는 빼고)를 선택한 후 확인 버튼을 누른다.













New Test Project 윈도우에 생성할 UnitTest 프로젝트 이름을 입력한다.













솔루션 탐색기를 보면 CalculateBasicTest.cs 파일을 가진 MathUnitTest 프로젝트가 생성됨을 확인할 수 있다. CalculateBasicTest.cs 파일을 보면 앞서 CalculateBasic.cs의 메소드를 테스할 메소드가 생성되어 있다. 각각의 메소드에서 Assert.Inconclusive 문장을 제거해 주자.













Step 3. Test Unit Test





Unit Test를 해보자!! 우선 수행하기 전에 CalculateBasicTest.cs에 정의된 각 테스트 메소드를 보자.


AddNumbersTest 메소드를 보면 AddNumbers 메소드로 전달할 매개변수, 예측 결과값, 실제 결과값 변수가 선언되어 있다. 주석문에 TODO 라고 써있는 것 처럼 매개변수와 예측 결과값을 직접 작성해줘야 한다. 초기값으로 0 으로 되어있으니 테스트할 값으로 수정해 주자. 다른 테스트 메소드들도 이와 같은 방법으로 수정해 주자.













메뉴에서 "Test → Debug → All Tests in Solution" 을 선택한다.













하단에 Test Results 윈도우에  테스트 결과가 표시된다. 













예측한 값과 결과 같이 다르면 아래와 같이 실패한 정보를 보여준다. 이밖에도 테스트 메소드에서 예외가 발생하가나 기타 다른 이유등의 실패 시에도 그 결과를 보여준다.













Step 4. Enable Code Coverage and Test Impact Analysis





Code Coverage와 Impact Analysis 테스트를 활성화 시키자. 


메뉴에서 "Test → Edit Test Settings → Local (local.testsettings)













Test Settings 윈도우에서 다음과 같이 선택해 준다.


  1. Data and Diagnostics 선택


  2. 오른쪽 하단의 Data and Diagnostics for selected role: 에서 Code Coverage 와 Test Impact 를 체크


  3. Code Coverage 를 선택한 다음 위쪽에 Configure 를 선택한다.













Code Coverage 를 위해 포함시킬 어셈블리를 체크해 준다. 여기선 두개 다 선택해주었다. 클래스 라이브러리 혼자 독립적으로 실행될 수 없으니 해당 클래스 라이브러리를 테스트할 어셈블리도 포함시켜줘야 한다.













Step 5. Check Code Coverage





테스트를 위해 DivideNumbers 메소드를 다음과 같이 수정한다.










다시 한번 Unit Test 를 진행한 후 Test Results 에서 임의의 테스트에 마우스를 가져간 다음 마우스 오른쪽 버튼을 누른다. 팝업 메뉴에서 Code Coverage Results 를 선택한다.













Code Coverage Results 윈도우에서 결과를 확인할 수 있다.










Unit Test에 의해 코드의 Covered 와 Not Covered 수치를 확인할 수 있다. AddNumbers 를 보면 Covered Block 이 100% 이므로 Unit Test에서 모든 블록이 Covered 됬음을 알 수 있다. DivideNumbers 를 보면 28.57%가 Not Covered 이다. DivideNumbers 항목을 마우스로 선택한 후 마우스 오른쪽 버튼으로 Go to Source Code를 선택하여 코드로 이동한다.





색으로 Covered 와 Not Covered 를 구분지어 놨다.













Step 6. Test Impact Analysis





Impact Analysis 테스트의 목적은 Unit Test에서 임의의 코드의 Impact(?)를 체크하는 것이다. 


테스트를 위해 SubstractNumbers 와 MultiplyNumbers 메소드를 다음과 같이 변경해준다.













Impact Test View를 활성화 시키자.


"Test → Windows → Test Impact View"













솔루션을 다시 빌드하면 Test Impact View 에 다음과 같이 결과를 출력해 준다.













MultiplyNumbersTest 에서 마우스 오른쪽 버튼을 눌러 "Run All Impacted Tests" 를 선택해 준다.













Impacted tests로 다시 Code Coverage Result를 확인한다.











음...  Unit Test 는 어떤 경우에 사용해야겠구나 생각이 드는데 나머지는 조금 어렵다...

[VS 2010] Default Key Binding

[VS 2010] Default Key Binding









 Visual Studio 2010 Default Key Binding 이다.  단축키를 잘 사용해야 업무 능력도 향상되는것 같다. 단축키 하나씩 눌러보고 몰랐던 VS의 기능도 알게되고 여러모로 좋다.
















2010년 7월 29일 목요일

[InstallShield 2008] InstallShield Script







InstallShield Script











 어쩌다 보니 InstallShield를 건들게(?) 되었다. 스크립트가 몬지... 딱 보니 델파이 소스 같기도 하고..


급히 알게된 것들이라.. 또 언제 급하게 하게 될지 몰라 정리해 둔다.








■ 전역 변수





전역 변수를 선언해서 사용할 수 있다.


최 상위에 선언해서 사용하면 된다.





BOOL isStart;







■ 상수 선언





#define MAX_LEN  100


#define NAME        "My Name"









■ if 문





if (condition) then


    // statements to be executed if condition is true


endif;








■ for 문 





for iCount = 1 to 10


        MessageBox ("This appears ten times.", INFORMATION);


endfor;


for iCount = 10 to 100 step 10


        MessageBox ("This appears ten times.", INFORMATION);


endfor;








■ while 문 





nCount = 1;


while (nCount < 5)


    MessageBox ("This is still true.", INFORMATION);


    nCount = nCount + 1;


endwhile;







■ switch 문





STRING szMsg, svResult;


NUMBER nvResult;


GetSystemInfo (VIDEO, nvResult, svResult);


    


switch (nvResult)


    case IS_UNKNOWN: 


        szMsg = "The user's video is unknown.";


    case IS_EGA:


        szMsg = "EGA resolution.";


    case IS_VGA:


        szMsg = "VGA resolution.";


    case IS_SVGA:


        szMsg = "Super VGA (800 x 600) resolution.";


    case IS_XVGA:


        szMsg = "XVGA (1024 x 768) resolution.";


    case IS_UVGA:


        szMsg = "Greater than 1024 x 768 resolution.";


    default:


        szMsg = "Error";


endswitch;









■ 사용자 함수 추가





- prototype 정의


- function body 정의





1. prototype 정의





protype GetPathParts(STRING, BYREF STRING, BYREF STRING, BYREF STRING);





※ 함수 파라미터러 BYVAL 과 BYREF 를 사용한다.


    BYVAL 은 매개변수를 값 타입 으로 넘긴다.


    BYREF 는 매개변수를 참조 타입으로 넘긴다. (C/C++ 의 포인터, 참조 변수라 생각하면 된다.)





2. function body 정의






function GetPathParts(szFullPath, svDrv, svPath, svName)


    LONG lResult;                                                                  // 함수에서 사용할 지역 변수 선언


begin                                                                                  // 함수의 실제 내용 시작


    lResult = ParsePath(svDrv, szFullPath, DISK);


    if (lResult = 0) then


        lResult = ParsePath(svPath, szFullPath, DIRECTORY);


    endif;


    if (lResult = 0) then


        lResult = ParsePath(svName, szFullPath, FILENAME);


    endif;


end;                                                                                    // 함수의 끝









■ C++ DLL 로드





1. 우선 사용할 DLL 을 준비 한다.





2. InstallShield 에서 Support Files/Billboard 탭 선택 후, Language Independent 를 선택한다.


   오른쪽 리스트에 해당 DLL을 추가해 준다.







3. 사용할 함수의 원형을 선언해준다.


   cf) DLL 이름이 parseString 이고 내부 함수가 CalSum 일 경우





prototype cdecl INT parseString.CalSum(BYVAL INT, BYVAL INT);





4. DLL을 로드 한다.





...


STRING szDllPath;


INT nResult;


...





szDllPath = SUPPORTDIR^"parseString.dll";     // DLL 파일 경로 지정


nResult = UseDLL(szDllPath);                        // DLL 로드


if (nResult == 0 ) then                                    // DLL 로드 실패하면 0을 리턴함



    abort;



endif;





nResult = CalSum(1,2);                                 // DLL 에 정의된 함수 사용





UnUseDLL(szDllPath);                                   // 사용한 dll 로드 해제








※ 함수 원형을 선언해 줄 때 cdecl 과 같은 키워드는 dll에 정의된 함수 타입에 따라 달라짐


※ 위 예제를 참조한 블로그 : 외부 dll 함수 호출하여 쓰기




2010년 7월 26일 월요일

정적 라이브러리에서 MFC 사용

정적 라이브러리에서 MFC 사용



 MFC 응용프로그램 배포 시, MFC 사용 방법을 프로젝트 설정에서 설정해준다.




공유 DLL에서 MFC 사용 : 응용프로그램 배포 시 mfc**.dll 파일을 함께 배포.

정적 DLL에서 MFC 사용 : 응용프로그램의 실행 파일에 mfc**.dll 이 포함되어 배포되기 때문에 응용프로그램만 배포.


  배포 시 응용프로그램만 배포하는게 관리하기도 편하고 오작동의 가능성도 적기 때문에 "정적 DLL 에서 MFC 사용" 으로 프로젝트를 설정하여 개발하게 된다.


  응용프로그램이 DLL 일 경우 위와 같이 설정하면 컴파일 시 다음과 같은 오류 메시지가 발생한다.

fatal error C1189: #error :  Please use the /MD switch for _AFXDLL builds


다음과 같이 설정해 주자.





1. 전처리기 정의

C/C++ → 전처리기 → 전처리기 정의

"_AFXDLL" 추가




2. 코드 생성

C/C++ → 코드 생성 → 런타임 라이브러리

Debug 모드일 경우    : "다중 스레드 디버드 DLL(/MDd)" 설정

Release 모드일 경우 :  "다중 스레드 DLL(/MD)" 설정







.NET Framework Version 과 배포

.NET Framework Version 과 배포


 .NET 응용프로그램 배포와 관련하여 많은 이슈를 접하게 되었다. 이슈를 해결하면서 참고한 자료들을 정리하였다.
원문은
.NET Framework 버전 정리하기 이며 추가로 몇몇 정보를 추가하였다.


■ .NET Framework Version

2010년 7월 현재 6개의 버전이 출시되었다.


(이미지 출처 : http://www.lifehack.kr/)



■ .NET Framework 의 사용

1) .NET Framework 은 독립적으로 실행된다.
  위에선 크게 4가지로 분류하셨는데 하나의 OS에서 1.0, 1.1, 3.5, 4.0 각각 설치가 가능하다. 4.0을 설치해도 그외 버전은 설치 되지 않으며, 1.1을 설치해도 1.0은 설치되지 않는다.

2) .NET 응용프로그램이 사용하는 .NET Framework 을 설치해주어야 한다.
  .NET 응용프로그램을 개발할 때 대상으로 하는 .NET Framework 버전이 있을 것이다. 해당 응용프로그램을 배포할 때 대상으로 하는 .NET Framework을 설치하는게 가장 좋다.
  특정 버전에 대응하는 응용프로그램을 다른 버전의 CLR에서 실행되는 것은 불가능 하지는 않다. .NET 응용프로그램의 환경 설정 파일인 *.config 를 수정해주면 된다고 한다. 그러나 하위 호환성이 완전하지는 않기 때문에 모든 환경에서 정확히 동작할 것이라는 보장은 없다. 이러한 주의점 때문에 .NET Framework 1.0/1.1/4 을 타겟으로 개발한다고 한다. 


3) .NET Framework 의 설치 순서도 주의해야 한다. 
  버전 1.1 과 4.0 을 사용하려고 할 때, 버전 1.1을 먼저 설치한 다음 4.0을 설치해야 한다. 즉, 버전이 낮은 버전부터 설치해야 한다. 4.0을 설치하고 1.1을 설치할 수는 없다.

4) 다른 버전을 포함하는 버전도 있다.
  버전 3.0 을 설치하면 버전 2.0도 설치가 된다. 또한 버전 3.5를 설치하면 버전 2.0/3.0이 설치가 된다.

5) .NET Framework 3.5 sp1 다운로드 설치 시 Windows Installer 3.1 이상 필요

  MSDN 에서 .NET Framework 3.5 sp1 을 다운받은 파일을 실행하면 인터넷으로 부터 .NET Framework 3.5 sp1 을 다운 받고 설치까지 수행해 준다. 하지만 해당 OS에 Windows Installer 3.1 이상이 설치되어 있지 않으면 .NET Framework 3.5 sp1 을 다운받지 못한다.





■ OS 와 .NET Framework 의 설치

(이미지 출처 : http://www.lifehack.kr/)

빨간색은 OS에 이미 설치되어 있는 버전이고, 파란색은 설치 가능한 버전을 나타낸다.



■  Visual Studio 설치와 .NET Framework


 Visual Studio 2008  .NET Framework 3.0 
 Visual Studio 2008 SP1 .NET Framework 3.5 
 Visual Studio 2010  .NET Framework 4.0 
 Visual Studio 2012  .NET Framework 4.5 




■  설치된 .NET Framework 버전 확인
설치된 .NET Framework 버전 확인 - MSDN



■ 참조


2010년 7월 25일 일요일

WPF 응용프로그램 수명 주기 - 묵시적 응용프로그램 생성

WPF 응용프로그램 수명 주기 - 묵시적 응용프로그램 생성










 업무에서는 사용하지 않지만 개인적으로 너무 끌려서(?) WPF를 공부하고 있다.  바쁘다는 핑계로 듬성듬성 공부하였더니 책 진도 상태는 맨날 그대로다.. 자! 마음 가다듬고 다시 시작해보자!!





내용은 "Programming WPF 사용자 경험(UX)을 바꾸는 기술 - 한빛 미디어" 책에 기술된 내용이다.





 대부분의 MFC를 공부하고 있는 사람들은 main 함수 즉, 프로그램의 진입점 함수가 어디에 정의되이 있는지 모를 것이다. 눈에 보이지 않으니 아무래도... WPF 에서도 대부분의 경우에 있어 main 함수를 컴파일러가 알아서 잘 만들어 준다.








WPF 프로젝트는 일반적으로 응용 프로그램(Application 클래스 인스턴스)을 정의하는 하나의 XAML 파일을 지정한다. 







(App.xaml 파일이 응용프로그램 즉, Application 인스턴스를 설정하는 XAML 파일이다.)








App.xaml 과 App.xaml.cs (코드 비하인드 파일) 에서 응용프로그램을 생성하며, 윈도우를 생성하고 보여준다.


















위에서 응용프로그램을 정의하는 XAML 파일(App.xaml) 을 빌드 작업 속성으로 "AppllicationDefinition" 으로 설정하면 WPF는 Application 이 정의되어 있는 것으로 간주하고 다음과 같은 작업을 수행한다. 










1. WPF 는 ApplicationDefinition 프로퍼티가 설정된 클래스를 응용 프로그램 클래스로 인식한다.


2. Main 함수를 생성한다.


3. 응용 프로그램 클래스의 인스턴스를 생성한다.


4. 응용 프로그램 인스턴스의 Run 메소드를 실행 시킨다.


5. Run 메소드는 OnStartup 이벤트를 발생시킨다.








위에서는 보여줄 윈도우가 Application 파생 클래스에 정의되어 있는 경우이고, 윈도우가 XAML 파일에 정의되어 있다면(대부분의 경우) Application 인스턴스의 StartupUri 프로퍼티에 XAML 파일을 연결시켜 준다.










StartupUri 프로퍼티를 이용할 경우





1. WPF 는 Application 의 인스턴스를 생성하고, 이 인스턴스에 대한 참조를 Application.Current 속성에 대입


2. StartupUri 프로퍼티에 지정된 XAML 에서 UI의 인스턴스를 생성하고 보여준다.


3. Application 객체의 MainWindow 프로퍼티가 설정된다. (아마 위에서 만든 윈도우겠지!)


4. Application 객체의 Run 메소드를  호출하여 MainWindow 가 닫힐 때까지 응용프로그램의 실행 상태를 유지











 main 함수를 직접 작성할 일은 없겠지만 WPF 응용프로그램이 어떤 식으로 초기화되어 생성되는지는 알고 있어야겠다. 어차피 마법은 없다. 



2010년 7월 22일 목요일

.NET 응용프로그램 배포 파일에 대하여

.NET 응용프로그램 배포 파일에 대하여



음... .NET 응용프로그램을 배포하는 방법으로 ClickOnce가 있긴 하지만 상용 응용프로그램을 배포 할때는 역시 InstallShiled를 사용한다. 배포할 파일을 선별하던 중 새로 알게되는 파일 정보를 정리한다.


1. vshost 파일

bin 폴더에 보면 실행파일 이름과 exe 확장자 사이에 "vshost" 이름이 붙은 파일들이 있다.


자세한 내용은 아래 링크를 참조!



간단히 정리해 보면
프로그램을 디버깅 하기 위해서 프로세스를 실행 시킬때 다음과 같은 작업이 선행적으로 이루어 진다.

- 프로세스의 실행을 위한 런타임 환경 구축
- 디버거 초기화

따라서 디버깅 할 때 속도가 느려지게 되는데 이 점을 보완해 주는 호스트 프로세스라고 한다.


이 밖에도 부분 트러스트 디버깅(Parial Trust Debugging), 디자인 타임 수식 평가(Design Time Expression Evaluation) 기능을 수행 한다고 한다. 

따라서 배포 파일에 포함되지 않아도 된다.



2. pdb 파일

Program DataBase 파일이라고 한다. 


프로그램을 컴파일 시 디버그 과정을 수행할 때 만들어 진다. 
디버깅 정보를 같이 배포할 필요가 없기 때문에 pdb 파일도 배포 파일에 포함되지 않아도 된다.

2010년 7월 18일 일요일

C# 추상 클래스 디자인 (Abstract class design)




C# 추상 클래스 디자인 (Abstract class design)










 책의 예제 코드를 코딩 하다가 Resharper 에서 코드에 경고가 있다가 표시해주고 있었다. 













상황은 그렇다.





Location 은 추상 클래스다. Location 의 생성자의 접근 지정자가 public 이므로 protected 로 변경하기를 추천(?) 한다는 것이다. 물론 public 으로 지정해도 컴파일은 된다. 





1. 추상 클래스의 public 생성자.


일단 public 생성자는 의미가 없다. public 생성자는 해당 클래스의 인스턴스를 만들  때 사용한다. 하지만 추상 클래스는 인스턴스를 생성할 수 없다. 





2. 추상 클래스의 protected 생성자.


protected 접근 지정자는 외부에서는 접근할 수 없지만, 그 클래스를 상속 받는 파생 클래스에서는 public 으로 접근할 수 있다는 소리다. 추상 클래스에서 protected 생성자를 추천하는 것는 추상 클래스를 상속 받는 파생클래스에서 파생 클래스 생성자가 부모 클래스 즉, 추상 클래스를 초기화 하기 위해 추상 클래스 생성자를 호출 할 수 있도록 지원하기 위해서 이다. 








MSDN에 추상클래스 디자인에 대한 자료가 있다. 






강조한 내용을 보면





"추상 형식에 public 또는 protected internal(Visual Basic의 경우 Protected Friend) 생성자를 정의하지 않습니다."


"추상 클래스에 protected 또는 internal 생성자를 정의합니다."


"사용자가 제공하는 각 추상 클래스에서 상속되는 하나 이상의 구체적인 형식을 제공합니다."





internal 은 같은 어셈블리내에서는 public 인데... protected internal 이와 이와 비슷하게... 조금은 이해가 가질 않지만 많이 사용하다 보면 이해가 가겠지...








MSDN에서 언급한 것처럼 올바르게 디자인 하고, 올바르게 사용할 줄 알아야 한다.




















2010년 7월 6일 화요일

[Coding Style] Enum 정의에 대하여.

Enum 정의에 대하여










 Coding Style에 있어 Enum 정의에 대해서 정리해 본다. 


Enum 을 정의할 때, 사용하는 클래스 안에서 정의하여 사용하곤 했다. 그런데 그 클래스에서 사용하는 Enum 형이 많아지다보니 해당 클래스의 코드가 상당히 길어져 코드를 보기 상당히 불편해 졌다. 어떻게 사용해야 할까 생각하다가 친구로 부터 도움을 받았다. 








1. Enum 타입만 정의할 파일을 생성한다.


  사용하려는 클래스가 정의된 파일과 분리된 파일에 정의하므로 코드를 간결하게 유지할 수 있다.





2. 네임스페이스 하위에 바로 작성한다.


  새로운 파일에 클래스를 새로 정의하여 클래스 멤버로 Enum을 정의할 수도 있다. 이 경우 Enum 접근을 위한 코드가 조금 더 길어질 수 있는 단점은 있다.


  네임스페이스 하위에 바로 Enum 을 정의하여 사용할 수 있다. 네임스페이스는 다른 타입들과 중복되지 않도록 특정한 이름을 주어 사용하는것이 좋다.


 Enum을 정의할 때 두가지 접근 지정자를 사용할 수 있다.





● internal


● public 





Enum 타입이 클래스 내부에 지정된 것이 아니므로 외부에서 Enum을 정의한 어셈블리로 접근할 때 Enum의 가시성에 대한 지정자만 사용 가능하다. internal은 어셈블리 내부에서만 사용할 수 있고, public 은 어셈블리 외부에서도 접근하여 사용 가능하다.







namespace MyApp.Common


{    


    /// <summary>


    /// 바이로봇 정책의 하위 아이템 타입


    /// </summary>


    internal enum ItemType


    {


         /// <summary>


         /// 알 수 없음


         /// </summary>


         Unknown = 0,


         ...


      }


}