그래프 구조를 사용하여 코드를 어떻게 단위 테스트합니까?


18

종속성 그래프를 탐색하는 (재귀 적 인) 코드를 작성 중이므로 종속성의 순환 또는 모순을 찾습니다. 그러나 단위 테스트에 어떻게 접근하는지 잘 모르겠습니다. 문제는 우리의 주요 관심사 중 하나는 발생할 수있는 모든 흥미로운 그래프 구조를 코드가 처리하고 모든 노드가 적절하게 처리되도록하는 것입니다.

일반적으로 100 % 라인 또는 분기 범위만으로도 일부 코드가 작동한다고 확신 할 수 있지만 100 % 경로 범위를 사용하더라도 의심 할 여지가 없습니다.

따라서 테스트 사례에 대한 그래프 구조를 선택하여 코드가 실제 데이터에서 찾을 수있는 모든 순열을 처리 할 수 ​​있다는 확신을 가지려면 어떻게해야합니까?


PS- 중요한 경우, 내 그래프의 모든 모서리는 "필수"xor "할 수 없음"으로 표시되며 사소한주기는 없으며 두 노드 사이에 하나의 모서리 만 있습니다.


PPS- 이 추가 문제 설명은 원래 질문 작성자가 아래 의견에 게시했습니다.

For all vertices N in forest F, for all vertices M, in F, such that if there are any walks between N and M they all must either use only edges labelled 'conflict' or 'requires'.


13
다른 방법을 단위 테스트하는 것과 같은 방법입니다. 각 방법에 대한 모든 "관심있는"테스트 사례를 식별하고 이에 대한 단위 테스트를 작성합니다. 귀하의 경우, 각각의 "흥미로운"그래프 구조에 대해 미리 준비된 종속성 그래프를 작성해야합니다.
Dunk

@ 덩크 우리는 우리가 다루기 어려운 까다로운 것들을 모두 가지고 있다고 생각하고 특정 구조가 이전에는 고려하지 않았던 문제를 야기한다는 것을 알고 있습니다. 우리가 생각할 수있는 모든 까다로운 것을 테스트하는 것은 우리가하고있는 일이며, 내가 찾고 싶은 것은 근본적인 형태의 환원성을 사용하여 귀찮은 예제 를 생성하기위한 지침 / 절차입니다 .
Sled

6
그것은 모든 형태의 테스트에서 발생하는 문제입니다. 당신이 아는 것은 당신이 생각하는 테스트가 작동한다는 것입니다. 테스트가 통과되었다고해서 sw에 오류가 없다는 것을 의미하지는 않습니다. 모든 프로젝트에는 동일한 문제가 있습니다. 현재 프로젝트를 제공하는 마지막 단계에 있으므로 제조를 시작할 수 있습니다. 현재 발생하는 오류 유형은 다소 모호한 경향이 있습니다. 예를 들어, 하드웨어가 여전히 사양에 따라 작동하지만 간신히 같은 문제를 가진 다른 하드웨어와 동시에 결합되면 문제가 발생합니다. 그러나 때로는 가끔 : (sw는 잘 테스트되었지만 우리는 모든 것을 생각하지 않았습니다
Dunk

설명하는 것은 단위 테스트가 아니라 통합 테스트와 비슷합니다. 단위 테스트는 방법이 그래프에서 원을 찾을 수 있는지 확인합니다. 다른 단위 테스트는 특정 그래프의 특정 원이 테스트중인 클래스에 의해 처리되는지 확인합니다.
SpaceTrucker

주기 탐지는 잘 다루는 주제이며 (아래 Knuth 및 일부 답변 참조) 솔루션에는 많은 특수한 사례가 포함되지 않으므로 먼저 문제를 일으키는 원인을 결정해야합니다. 당신이 언급 한 모순 때문입니까? 그렇다면 더 자세한 정보가 필요합니다. 구현 선택의 결과 인 경우 아마도 리팩토링해야 할 수도 있습니다. 근본적으로, 이것은 당신이 길을 생각해야 할 디자인 문제입니다. TDD는 당신이 막 다른 골목에 들어가기 전에 미로에 깊숙이 들어갈 수있는 잘못된 접근법입니다.
sdenham

답변:


5

우리는 우리가 다루기 어려운 까다로운 것들을 모두 가지고 있다고 생각하고 특정 구조가 이전에는 고려하지 않았던 문제를 야기한다는 것을 알고 있습니다. 우리가 생각할 수있는 모든 까다로운 테스트는 우리가하는 일입니다.

좋은 시작 인 것 같습니다. 이미 범위 기반 테스트를 언급했듯이 경계 값 분석 또는 동등 분할 과 같은 일부 고전적인 기술을 적용하려고 시도한 것 같습니다 . 좋은 테스트 사례를 구성하는 데 많은 시간을 투자 한 후에는 귀하, 팀 및 테스터 (있는 경우)가 아이디어를 잃을 수있는 시점에 도달하게됩니다. 이것이 바로 단위 테스트 의 길을 떠나 가능한 많은 실제 데이터로 테스트를 시작 해야하는 시점 입니다.

생산 데이터에서 다양한 그래프를 선택해야합니다. 프로세스의 해당 부분에 대해서만 추가 도구 나 프로그램을 작성해야 할 수도 있습니다. 여기서 어려운 부분은 아마도 프로그램 출력의 정확성을 확인하는 것입니다. 만일 다른 실제 그래프를 프로그램에 넣을 때 프로그램이 항상 올바른 출력을 생성하는지 어떻게 알 수 있습니까? 분명히 수동보다 확인할 수 없습니다. 운이 좋으면 종속성 검사를 두 번째로 매우 간단하게 구현하여 성능 기대치를 충족 시키지는 않지만 원래 알고리즘보다 확인하기가 더 쉽습니다. 또한 많은 타당성 검사를 프로그램에 직접 통합해야합니다 (예 :

마지막으로, 모든 테스트는 버그가 있음을 증명할 수 있지만 버그가없는 것은 아니라는 점을 인정하는 법을 배웁니다.


5

1. 무작위 테스트 생성

그래프를 생성하는 알고리즘을 작성하고 수백 (또는 그 이상)의 랜덤 그래프를 생성 한 다음 알고리즘에 각각 던지십시오.

흥미로운 실패를 일으키는 그래프의 무작위 시드를 유지하고이를 단위 테스트로 추가하십시오.

2. 까다로운 하드 코드

알고있는 일부 그래프 구조는 까다로워 코딩하거나이를 결합하여 알고리즘으로 푸시하는 코드를 작성할 수 있습니다.

3. 철저한 목록 생성

그러나 "코드가 실제 데이터에서 찾을 수있는 모든 가능한 순열을 처리 할 수 ​​있습니다"라고 확신하려면 임의의 시드가 아니라 모든 순열을 통해이 데이터를 생성해야합니다. (이는 지하철 철도 신호 시스템을 테스트 할 때 수행되며 테스트하는 데 오랜 시간이 걸리는 사례를 제공합니다. 지하철 지하철의 경우 시스템이 제한되어 있으므로 순열 수의 상한이 있습니다. 적용)


질문자는 자신이 모든 사례를 고려했는지 여부를 알 수 없다고했으며, 이는 사례를 열거 할 방법이 없음을 의미합니다. 그들이 문제 영역을 충분히 이해할 수있을 때까지 테스트하는 방법은 문제가됩니다.
sdenham

@ sdenham 무한한 유효한 조합의 수를 문자 그대로 열거하는 방법은 무엇입니까? 나는 "이것들은 종종 당신의 구현에서 버그를 잡을 수있는 가장 까다로운 그래프 구조들"이라는 라인을 따라 무언가를 찾고자했다. 도메인이 간단하기 때문에 도메인을 충분히 이해합니다 For all vertices N in forest F, for all vertices M, in F, such that if there are any walks between N and M they all must either use only edges labelled 'conflict' or 'requires'.. 도메인은 문제가 아닙니다.
Sled

@ArtB : 문제를 명확하게 해주셔서 감사합니다. 두 정점 사이에 하나 이상의 모서리가 없으며 사이클을 사용하여 경로를 배제하는 것으로 보이는 경우 (또는 모든 사이클 주위에 하나 이상의 패스가 있음) 적어도 문자 그대로 무한한 숫자가 없다는 것을 알고 있습니다. 가능한 유효한 조합으로 진행됩니다. 모든 가능성을 열거하는 방법을 아는 것은 정확성을 주장하는 출발점이 될 수 있으므로 테스트를 안내 할 수 있기 때문에 반드시해야한다고 말하는 것과는 다릅니다. 나는 더 많은 생각을 할 것이다 ...
sdenham

@ArtB : 여기에 주어진 문제 설명에 대한 업데이트를 포함하도록 질문을 수정해야합니다. 또한 이러한 방향이 모서리에 해당하고 (있는 경우) 알고리즘이 처리해야하는 상황이 아니라 그래프에서 사이클이 오류로 간주되는지 여부를 설명하는 데 도움이 될 수 있습니다.
sdenham

4

이 경우 충분한 실제 데이터 나 퍼지조차도 충분하지 않은 테스트는 없습니다. 재귀 함수를 테스트하기에는 100 % 코드 범위 또는 100 % 경로 범위가 충분하지 않습니다.

재귀 함수는 공식적인 증거 (이 경우 그렇게 어렵지 않아야 함)를 나타내거나 그렇지 않습니다. 부작용을 배제하기 위해 코드가 응용 프로그램 특정 코드와 너무 얽혀 있으면 시작해야합니다.

알고리즘 자체는 간단한 광범위한 첫 번째 검색과 유사한 간단한 플러딩 알고리즘처럼 들리며 블랙리스트를 추가하여 방문한 노드 목록과 교차해서는 안되며 모든 노드에서 실행됩니다.

foreach nodes as node
    foreach nodes as tmp
        tmp.status = unmarked

    tovisit = []
    tovisit.push(node)
    node.status = required

    while |tovisit| > 0 do
        next = tovisit.pop()
        foreach next.requires as requirement
            if requirement.status = unmarked
                tovisit.push(requirement)
                requirement.status = required
            else if requirement.status = blacklisted
                return false
        foreach next.collides as collision
            if collision.status = unmarked
                requirement.status = blacklisted
            else if requirement.status = required
                return false
return true

이 반복 알고리즘은 임의의 아티팩트에서 시작하여 항상 아티팩트가 시작되는 임의의 구조 그래프에 대해 종속성이 필요하지 않고 동시에 블랙리스트에 올릴 수있는 조건을 충족합니다.

자체 구현만큼 빠르거나 빠를 수는 없지만 모든 경우에 대해 종료된다는 것이 입증 될 수 있습니다 (외부 루프의 각 반복마다 각 요소는 tovisit큐에 한 번만 푸시 될 수 있음). 각 노드에서 시작하여 아티팩트가 필요하고 동시에 블랙리스트에 등록되어야하는 모든 경우를 감지합니다.

자체 구현에 동일한 특성이 있음을 보여줄 수 있으면 단위 테스트를 수행하지 않고도 정확성을 입증 할 수 있습니다. 대기열에서 푸시 및 팝, 대기열 길이 계산, 속성 반복 등의 기본 방법 만 테스트하여 부작용이 없어야합니다.

편집 : 이 알고리즘이 증명하지 못하는 것은 그래프에 사이클이 없다는 것입니다. 직접 비순환 그래프 는 잘 연구 된 주제이므로이 속성을 증명할 준비가 된 알고리즘을 찾는 것도 쉬워야합니다.

보시다시피 바퀴를 전혀 재발 명할 필요가 없습니다.


3

"모든 흥미로운 그래프 구조"및 "적절하게 처리"와 같은 문구를 사용하고 있습니다. 이러한 모든 구조에 대해 코드를 테스트하고 코드가 그래프를 적절하게 처리하는지 여부를 결정하는 방법이 없다면 테스트 범위 분석과 같은 도구 만 사용할 수 있습니다.

여러 가지 흥미로운 그래프 구조를 찾아 테스트하여 시작하고 적절한 처리 방법을 결정하고 코드가이를 수행하는지 확인하는 것이 좋습니다. 그런 다음 해당 그래프를 a) 규칙을 위반하는 깨진 그래프 또는 b) 문제가없는 관심없는 그래프로 섭동 할 수 있습니다. 코드가 제대로 처리하지 못하는지 확인하십시오.


이것은 테스트에 대한 좋은 접근 방법이지만 질문의 중심적 문제를 해결하지는 못합니다. 모든 사례를 보장하는 방법. 나는 더 많은 분석과 리팩토링이 필요할 것이라고 생각합니다-위의 질문을 참조하십시오.
sdenham


2

이런 종류의 테스트하기 어려운 알고리즘에 관해서는 테스트를 기반으로 알고리즘을 빌드하는 TDD를 사용합니다.

한마디로 TDD

  • 시험을 쓰다
  • 그것이 실패 참조
  • 코드를 수정
  • 모든 테스트를 통과했는지 확인하십시오
  • 리팩터링

주기를 반복하십시오.

이 특별한 상황에서

  1. 첫 번째 테스트는 알고리즘이 사이클을 반환해서는 안되는 단일 노드 그래프입니다.
  2. 두 번째는 알고리즘이 사이클을 반환하지 않아야하는 사이클이없는 3 개의 노드 그래프입니다
  3. 다음은 알고리즘이 사이클을 반환해서는 안되는 사이클에 세 개의 노드 그래프를 사용하는 것입니다.
  4. 이제 가능성에 따라 좀 더 복잡한주기에 대해 테스트 할 수 있습니다

이 방법의 중요한 측면 중 하나는 가능한 단계에 대한 테스트를 항상 추가해야하며 (가능한 시나리오를 간단한 테스트로 분할하는 경우) 가능한 모든 시나리오를 다루는 경우 일반적으로 알고리즘이 자동으로 진화됩니다.

마지막으로 예기치 않은 문제가 있는지 확인하기 위해 하나 이상의 복잡한 통합 테스트를 추가해야합니다 (예 : 그래프가 매우 크거나 재귀를 사용할 때 스택 오버플로 오류 / 성능 오류)


2

원래 언급 된 다음 Macke의 답변 아래 주석으로 업데이트 된 문제에 대한 나의 이해에는 다음이 포함됩니다. 1) 두 가지 에지 유형 (종속성 및 충돌)이 지시됩니다. 2) 두 노드가 한 에지로 연결된 경우 다른 노드이거나 반대의 경우에도 다른 노드로 연결해서는 안됩니다. 3) 서로 다른 유형의 에지를 혼합하여 두 노드 사이의 경로를 구성 할 수 있다면 무시되는 상황이 아니라 오류입니다. 4) 한 유형의 모서리를 사용하는 두 노드 사이에 경로가 있으면 다른 유형의 모서리를 사용하여 두 노드 사이에 다른 경로가 없을 수 있습니다. 5) 단일 에지 유형 또는 혼합 에지 유형의 사이클은 허용되지 않습니다 (응용 프로그램의 추측으로는 충돌 전용 사이클이 오류인지 확실하지 않지만이 조건을 제거 할 수는 없습니다).

또한, 사용 된 데이터 구조가 이러한 요구 사항의 위반이 표현되는 것을 막지 못한다고 가정합니다 (예 : 노드 쌍이 항상 노드 쌍에서 (유형, 방향)으로 맵에서 조건 2를 위반하는 그래프를 표현할 수 없음) 가장 적은 수의 노드가 먼저 있습니다.) 특정 오류를 표현할 수없는 경우 고려할 사례 수가 줄어 듭니다.

실제로 여기에서 고려할 수있는 세 가지 그래프가 있습니다 : 하나의 에지 유형 중 두 가지 유형과 두 유형 중 하나의 조합으로 구성된 혼합 그래프. 이를 사용하여 최대 수의 노드까지 모든 그래프를 체계적으로 생성 할 수 있습니다. 먼저 두 개의 정렬 된 노드 쌍 사이에 하나 이상의 에지를 갖는 N 노드의 가능한 모든 그래프를 생성하십시오 (이것은 방향성 그래프이기 때문에 정렬 된 쌍입니다). 이러한 그래프의 가능한 모든 쌍을 가져 오십시오. 하나는 종속성을 나타내고 다른 하나는 충돌을 나타냅니다. 각 쌍의 조합을 형성하십시오.

데이터 구조가 조건 2의 위반을 표현할 수없는 경우 종속성 그래프의 공간에 맞거나 그 반대의 가능한 모든 충돌 그래프 만 구성하여 고려할 사례를 크게 줄일 수 있습니다. 그렇지 않으면 공용체를 형성하는 동안 조건 2의 위반을 감지 할 수 있습니다.

첫 번째 노드에서 결합 된 그래프의 폭이 넓은 순회에서 모든 도달 가능한 노드에 대한 모든 경로 세트를 빌드 할 수 있으며 그렇게하면 모든 조건의 위반을 확인할 수 있습니다 (사이클 감지의 경우 사용 Tarjan의 알고리즘을 .)

다른 노드의 경로는 다른 경우 첫 번째 노드의 경로로 표시되므로 그래프가 연결 해제 된 경우에도 첫 번째 노드의 경로 만 고려해야합니다.

혼합 에지 경로가 오류가 아니라 단순히 무시 될 수있는 경우 (조건 3), 종속성 및 충돌 그래프를 독립적으로 고려하고 노드 중 하나에 도달 할 수 있는지 확인하면 충분합니다.

N-1 노드의 그래프 검사에서 발견 된 경로를 기억하면 N 노드의 그래프를 생성하고 평가하기위한 시작점으로 사용할 수 있습니다.

이것은 노드간에 동일한 유형의 여러 모서리를 생성하지 않지만이를 확장 할 수 있습니다. 그러나 이는 사례 수를 크게 증가 시키므로 테스트중인 코드로이를 표시하기가 불가능하거나 실패한 경우 사전에 그러한 사례를 모두 필터링하지 않는 것이 좋습니다.

이와 같이 오라클을 작성하는 비결은 그것이 비효율적이라는 것을 의미하더라도 가능한 한 간단하게 유지하여 신뢰를 확립 할 수 있도록하는 것입니다.

테스트 사례를 생성 할 수단이 있고 제품을 불량과 정확하게 분리하기 위해 생성 한 오라클을 신뢰하면이를 사용하여 대상 코드의 자동 테스트를 수행 할 수 있습니다. 이것이 가능하지 않은 경우, 다음 최선의 선택은 독특한 경우에 대한 결과를 살펴 보는 것입니다. 오라클은 찾은 오류를 분류하고 각 유형의 경로 수와 길이, 두 유형의 경로 시작 부분에 노드가 있는지 여부 등 허용 된 사례에 대한 정보를 제공 할 수 있습니다. 전에 보지 못한 사례를 찾는 데 도움이 될 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.