C++에서 Reflection을 하려면...

맹고이의 이미지

안녕하세요. 요즘 제가 간단히 쓸 C++ UnitTest Framework를 틈틈히 만들어 보고 있는데요. 구현을 하는 중에 어려운 점이 있어서 질문을 드리려고 합니다. '테스트 주도 개발'에서 파이썬을 이용해 xUnit을 만드는 것을 참고하면서 만들고 있는데요. 책의 예제를 잠시 인용하자면:

class TestCase:
  def __init__(self, name):
    self.name = name
  def run(self):
    method = getattr(self, self.name)
    method()

멤버 함수 테이블을 만들어서 구현할 수도 있을 것 같지만, RTTI를 이용해서 구현하고 싶은데 어떻게 해야될 지 모르겠네요(이리저리 찾아보니 Pluggable Selector라고 부르는 것 같네요).

간단한 방법 알고 계시면 조언 부탁드립니다. :)

colus의 이미지

온라인에서 Thinking in C++ 최신판을 보시면 C++로 된 UnitTestingFramework을 씁니다. 제 기억에 템플릿이나 매크로를 이용한 구현이 아니였습니다. 그럼 아마 RTTI겠죠.

맹고이의 이미지

Thinking in C++ 2nd Ed. 를 가지고 있는데, 그런 내용이 없네요. :(

TC++PL을 뒤져보다가, TestCase 생성자에서 멤버 함수 이름을 인자로 받는 대신, 멤버 함수 포인터를 받아서 처리하기로 했습니다. 생각해보니 어짜피 TestCase 하나는 테스트 하나를 실행하니까 상관없겠더라구요.

익명 사용자의 이미지

C++ 로만 해결하는 방법이 아니긴 하지만, 타 스크립트 언어로 C++ 코드를 파싱한뒤 이를 이용하여 code generation 하는 방법도 있습니다. 파싱하는 방법은 간단하게는 정규표현식을 쓰거나 파서를 만드는게 있겠습니다. CUT 과 CxxTest 라는 UT Framework가 이러한 방법을 씁니다. (perl 혹은 python 을 이용합니다)

장점은 C++ 에서도 리플랙션을 지원언어의 UT Framework의 장점(예를 들어 테스트 메소드 자동 등록)을 구현할 수 있다는 점이 있습니다. 그대신 단점으로는, 파싱결과에 따라 오동작할 수 있다는 점과, Test Case 상속에 대한 구현이 좀 어렵다는 점이 있었습니다.

익명 사용자의 이미지

cedar의 이미지

맹고이 wrote:
Thinking in C++ 2nd Ed. 를 가지고 있는데, 그런 내용이 없네요. :(

Thinking in C++은 2권으로 되어 있습니다.
'Volume Two: Practical Programming' pp.70-87에
'A simple unit test framework' 섹션을 참고하세요.
자세히 안 읽어봤지만, 간단히 매크로를 사용해서 구현했습니다.
맹고이의 이미지

[1002 wrote:
"]C++ 로만 해결하는 방법이 아니긴 하지만, 타 스크립트 언어로 C++ 코드를 파싱한뒤 이를 이용하여 code generation 하는 방법도 있습니다. 파싱하는 방법은 간단하게는 정규표현식을 쓰거나 파서를 만드는게 있겠습니다. CUT 과 CxxTest 라는 UT Framework가 이러한 방법을 씁니다. (perl 혹은 python 을 이용합니다)

장점은 C++ 에서도 리플랙션을 지원언어의 UT Framework의 장점(예를 들어 테스트 메소드 자동 등록)을 구현할 수 있다는 점이 있습니다. 그대신 단점으로는, 파싱결과에 따라 오동작할 수 있다는 점과, Test Case 상속에 대한 구현이 좀 어렵다는 점이 있었습니다.

답변 감사드립니다. 지금 의도가 CppUnit은 너무 무겁고, CppUnitLite는 xUnit 인터페이스가 아니라서 그냥 새로 한 번 만들어보고 있는 중인데요. 다른 스크립트 언어를 끌어들이면 더 번거로워 질 것 같아서 그 방법은 제외하고 있습니다. ^^;

일단은 CppUnit이 어떻게 처리하는지 소스를 좀 더 유심히 살펴봐야겠습니다.

맹고이의 이미지

colus wrote:
온라인에서 Thinking in C++ 최신판을 보시면 C++로 된 UnitTestingFramework을 씁니다. 제 기억에 템플릿이나 매크로를 이용한 구현이 아니였습니다. 그럼 아마 RTTI겠죠.

cedar wrote:
맹고이 wrote:
Thinking in C++ 2nd Ed. 를 가지고 있는데, 그런 내용이 없네요. :(

Thinking in C++은 2권으로 되어 있습니다.
'Volume Two: Practical Programming' pp.70-87에
'A simple unit test framework' 섹션을 참고하세요.
자세히 안 읽어봤지만, 간단히 매크로를 사용해서 구현했습니다.

다시 찾아보니 Thinking in C++ Vol.2가 다른 버전이 있었네요. 잠시 살펴보았는데, typeid를 이용해서 클래스 이름을 알아서 찍어주는 정도네요. 제가 원하는 것은 TestCase를 상속한 클래스에서 Run 멤버 함수를 호출할 때, 디폴트 생성자로 인스턴스를 만들었을 경우 "^Test*"로 시작하는 모든 멤버 함수를 실행시켜주고, 생성자에서 테스트할 멤버 함수 이름을 지정해줬을 경우, 해당 멤버 함수를 실행해주는 기능을 만들고 싶었습니다.

lovewar의 이미지

맹고이 wrote:
colus wrote:
온라인에서 Thinking in C++ 최신판을 보시면 C++로 된 UnitTestingFramework을 씁니다. 제 기억에 템플릿이나 매크로를 이용한 구현이 아니였습니다. 그럼 아마 RTTI겠죠.

cedar wrote:
맹고이 wrote:
Thinking in C++ 2nd Ed. 를 가지고 있는데, 그런 내용이 없네요. :(

Thinking in C++은 2권으로 되어 있습니다.
'Volume Two: Practical Programming' pp.70-87에
'A simple unit test framework' 섹션을 참고하세요.
자세히 안 읽어봤지만, 간단히 매크로를 사용해서 구현했습니다.

다시 찾아보니 Thinking in C++ Vol.2가 다른 버전이 있었네요. 잠시 살펴보았는데, typeid를 이용해서 클래스 이름을 알아서 찍어주는 정도네요. 제가 원하는 것은 TestCase를 상속한 클래스에서 Run 멤버 함수를 호출할 때, 디폴트 생성자로 인스턴스를 만들었을 경우 "^Test*"로 시작하는 모든 멤버 함수를 실행시켜주고, 생성자에서 테스트할 멤버 함수 이름을 지정해줬을 경우, 해당 멤버 함수를 실행해주는 기능을 만들고 싶었습니다.

여담으로 Test로 시작하는 멤버함수들을 무순서로 테스트하는 것은
아마도 그 순서가 정해지지 않아도 괜찮거나 precondition 또는 postcondition들의 상태값들을 각 Test로 시작하는 멤버함수들에서
제조정을 했다는 가정이 있을것으로 생각합니다.

시나리오 없이 테스트하는 것은 위험한 일인것 같습니다만, 그 업무을 알지 못하니 이론적인 것으로 마무리 합니다.

http://www.xprogramming.com/software.htm

위사이트는 방문했을 것으로 생각합니다만, 다른 분들을 위해 적어둡니다.

맹고이의 이미지

lovewar wrote:
맹고이 wrote:
colus wrote:
온라인에서 Thinking in C++ 최신판을 보시면 C++로 된 UnitTestingFramework을 씁니다. 제 기억에 템플릿이나 매크로를 이용한 구현이 아니였습니다. 그럼 아마 RTTI겠죠.

cedar wrote:
맹고이 wrote:
Thinking in C++ 2nd Ed. 를 가지고 있는데, 그런 내용이 없네요. :(

Thinking in C++은 2권으로 되어 있습니다.
'Volume Two: Practical Programming' pp.70-87에
'A simple unit test framework' 섹션을 참고하세요.
자세히 안 읽어봤지만, 간단히 매크로를 사용해서 구현했습니다.

다시 찾아보니 Thinking in C++ Vol.2가 다른 버전이 있었네요. 잠시 살펴보았는데, typeid를 이용해서 클래스 이름을 알아서 찍어주는 정도네요. 제가 원하는 것은 TestCase를 상속한 클래스에서 Run 멤버 함수를 호출할 때, 디폴트 생성자로 인스턴스를 만들었을 경우 "^Test*"로 시작하는 모든 멤버 함수를 실행시켜주고, 생성자에서 테스트할 멤버 함수 이름을 지정해줬을 경우, 해당 멤버 함수를 실행해주는 기능을 만들고 싶었습니다.

여담으로 Test로 시작하는 멤버함수들을 무순서로 테스트하는 것은
아마도 그 순서가 정해지지 않아도 괜찮거나 precondition 또는 postcondition들의 상태값들을 각 Test로 시작하는 멤버함수들에서
제조정을 했다는 가정이 있을것으로 생각합니다.

시나리오 없이 테스트하는 것은 위험한 일인것 같습니다만, 그 업무을 알지 못하니 이론적인 것으로 마무리 합니다.

http://www.xprogramming.com/software.htm

위사이트는 방문했을 것으로 생각합니다만, 다른 분들을 위해 적어둡니다.

당연히 각 테스트간에 의존성은 없어야 되니, 무순서로 테스트가 가능해야될 것 같구요. 하나의 TestCase에서 여러 테스트를 호출하면 precondition, postcondition이 바뀔 수 있다는 건 미처 생각을 못했네요. 각각의 "^Test*" 멤버 함수를 호출할 때마다 앞뒤로 Setup, Teardown을 호출하도록 해야겠습니다.

litdream의 이미지

DejaGNU 는 어떠신지요?

저도 unit test 를 사용해서, 프로그램의 정확도를 높이려고 하지만,
unit test 의 코드를 유지/보수 해야한다는 압박도 만만치 않죠.
지금은 회사업무때문에 기회를 잡지 못했지만, DejaGnu 라는 tcl 을 사용한
테스트를 저희 팀원이 보여주었는데, 훨씬 유연하고, 유지보수가 간편한것
같았습니다.

삽질의 대마왕...

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.