5

단위 테스트에 가장 적합한 방법으로는 컴파일러와 같은 복잡한 단위가 있습니까?단위 테스트 컴파일러

필자는 지난 몇 년 동안 컴파일러와 인터프리터를 작성 했으므로 이런 종류의 코드는 좋은 방법으로 테스트하기가 어렵습니다.

우리는 추상 구문 트리 생성과 같은 것을 사용합니다. TDD를 사용하여 어떻게 테스트합니까?

작은 구조는 테스트하기 쉽습니다. 예 :

string code = @"public class Foo {}"; 
AST ast = compiler.Parse(code); 

이렇게하면 노드가 많이 생성되지 않습니다.

하지만 실제로 컴파일러는 방법 같은 것을위한 AST를 생성 할 수 있는지 테스트하려면 :

[TestMethod] 
public void Can_parse_integer_instance_method_in_class() 
{ 
    string code = @"public class Foo { public int method(){ return 0;}}"; 
    AST ast = compiler.Parse(code); 

당신은 무엇에 주장하는 것입니까? 주어진 코드를 나타내는 AST를 수동으로 정의하고 생성 된 AST가 수동으로 정의 된 AST를 준수한다는 주장을 끔찍하게 혼란스럽게 만들고 오류가 발생할 수도 있습니다.

이렇게 복잡한 시나리오를 TDD로 처리하는 가장 좋은 방법은 무엇입니까?

+0

단위 테스트가 쓸모없고 열등한 이유의 수많은 예 중 하나 일 뿐이며 통합 테스트에 초점을 맞추어야합니다. TDD는 심각한 문제가 아니라 CRUD를위한 것입니다. 컴파일러의 경우 무작위로 생성 된 코드 테스트가 최선의 방법입니다. 예 : http://www.cs.utah.edu/~regehr/papers/pldi11-preprint.pdf –

+0

안전한 컴파일러 작성에 대한 더 나은 접근법에 관심이있을 수 있습니다. http://compcert.inria.fr/doc /index.html - 공식 사양은 가능한 모든 테스트보다 품질을 확실히 보장합니다. –

+0

@peer, 무슨 "방법"을 말하는거야? 구문 분석기가 생성되면 ('bison'이라고 생각하면) 모 놀리 식 문법과 생성 된 코드 더미를 읽을 수 없습니다. 문법 전체를 테스트 할 필요가 없습니다. 필기체의 재귀 파서 인 경우 단위 테스트 (예 : Clang 소스 코드를보고 작은 파서 항목마다 ASTContext와 입력 스트림을 조롱하는 방법을 생각해보십시오.)하기가 더 어렵습니다. 합리적으로 복잡한 코드의 경우 유닛 테스트는 사실상 무의미합니다. –

답변

1

먼저 구문 분석은 일반적으로 컴파일러 프로젝트의 간단한 부분입니다. 제 경험으로는 시간의 10 % 이상을 필요로하지 않습니다 (C++에 대해 말하지 않는 한, 당신이 설계한다면 질문하지 않을 것입니다). 그래서 파서 테스트에 많은 시간을 투자하지 않을 것입니다.

그래도 TDD (또는 사용자라고 부름)는 중간 엔드를 개발하는 데있어 공유하고 있습니다. 실제로 추가 한 최적화로 인해 예상되는 코드 변환이 발생했습니다. 필자의 경험에 비추어 볼 때, 보통 이와 같은 테스트는 컴파일러에게 특별히 제작 된 테스트 프로그램을 제공하고 예상되는 패턴에 대해 출력 어셈블리를 그려줌으로써 구현됩니다 (이 루프는 4 번 풀린 것인가? 그랩 어셈블리는 구조화 된 표현 (S-exprs 또는 XML)을 분석하는 것만 큼 좋지 않지만 대부분의 경우에 저렴하고 제대로 작동합니다. 컴파일러가 성장함에 따라 지원하기가 어렵습니다.

+0

전에 실제로 테스트에서 s- 표현식을 사용했습니다. 예. 내 AST에서 ToString() 자체를 s- 표현식으로 변환 할 수있게 만든 다음 결과가 예상되는 s- 표현식과 동일하다는 것을 간단하게 주장합니다. 그러나 hack'ish를 느낄 수 있지만 멋지게 작동합니다. 또는? –

+0

글쎄, 그것은 hackish하지만 일반적으로 사람들은 그걸로 살기를 선택하고 테스트에 너무 많은 시간을 투자하지 않습니다 (아무도 정말로 테스트하는 것을 좋아하지 않습니다). 서브 표현식에 대해서만 grep하고/또는 허용 오차 (다른 레지스터 또는 레이블 이름)를 허용하는 데 도움이 될 수 있습니다. – yugr

+0

여기에 좋은 예가 있습니다 : [LLVM의 조명 기반 구조] (http : //llvm.org/docs/TestingGuide.html) – yugr

4

첫째, 컴파일러를 테스트하면 충분한 테스트를 얻을 수 없습니다! 사용자는 항상 컴파일러가 생성 한 출력을 항상 황금의 표준 인 것처럼 신뢰할 수 있으므로 실제로 품질을 알고 있어야합니다. 그렇게 할 수 있다면 모든 테스트를 통해 테스트 해 볼 수 있습니다.

둘째, 사용 가능한 모든 테스트 방법을 사용하고 적절한 경우 사용하십시오. 실제로, 특정 변환이 정확하다는 것을 수학적으로 증명할 수 있습니다. 그렇게 할 수 있다면 그렇게해야합니다.

그러나 내부적으로 보아온 모든 컴파일러에는 휴리스틱과 내부적으로 최적화 된 수작업 코드가 많이 포함되어 있습니다. 따라서 보조 증명 방법은 일반적으로 더 이상 적용 할 수 없습니다. 여기에서 테스트가 이루어지며 많은 의미가 있습니다! 테스트를 수집 할 때

는 다른 경우를 고려하시기 바랍니다 :

  1. 긍정적 인 표준 적합성 : 당신의 프론트 엔드는 특정 코드 패턴을 수용해야하며, 컴파일러는 그 제대로 실행 프로그램을 생성해야합니다.이 범주의 테스트에는 테스트 프로그램의 올바른 출력을 생성하는 골든 레퍼런스 컴파일러 또는 생성기가 필요합니다. 또는 인간 추론에 의해 제공된 가치들에 대한 점검을 포함하는 수기 프로그램을 포함한다.
  2. 네거티브 테스트 : 모든 컴파일러는 구문 오류, 형식 불일치 등의 잘못된 코드를 거부해야합니다. 특정 유형의 오류 및 경고 메시지를 생성해야합니다. 나는 그러한 테스트를 자동으로 생성하는 방법을 모른다. 그래서 이것들은 인간이 써야 할 필요가 있습니다.
  3. 변환 테스트 : 컴파일러 (중간 엔드)에서 고급 최적화를 생각할 때마다 최적화를 보여주는 몇 가지 예제 코드가있을 수 있습니다. 이러한 모듈 전후의 변환에 대해 알아두면 컴파일러 나 해당 모듈이 플러그인 된 베어 본 컴파일러에 특별한 옵션이 필요할 수 있습니다. 합리적으로 큰 주변 모듈 조합을 테스트하십시오. 나는 대개 특정 변형 전후의 중간 표현에 대한 회귀 테스트를 수행하여 동료와의 집중적 인 추론을 통해 참조를 정의했습니다. 변환의 양면에 코드를 작성하십시오. 예를 들어, 변환하지 않고는 안되는 코드 스니 j을 변환하십시오.

이제는 엄청난 노력처럼 들립니다. 그렇습니다.하지만 도움이됩니다. (C-) 컴파일러를위한 상용 테스트 스위트가 여러 개 있으며 전문가를 적용하는 데 도움이 될 전문가가 있습니다. 나에게 알려진 사람들의 여기 작은 : 목록 GCC와 LLVM 환경

  • 당신이 그것을 이름으로

  • +1

    이것은 고귀한 고수준 통합 테스트입니다. 그다지 사랑받지 못한 이상한 "단위 테스트"가 아닙니다. 웹 코딩 힙합들에 의해. –