문제

우리는 객체에 대해 잠재적으로 오래 실행되는 계산을 수행하는 비동기적인 작업이 있습니다. 그런 다음 결과가 물체에 캐시됩니다. 여러 작업이 동일한 작업을 반복하지 않도록 원자력 SQL 업데이트로 잠금을 추가했습니다.

UPDATE objects SET locked = 1 WHERE id = 1234 AND locked = 0

잠금은 비동기 작업에만 해당됩니다. 객체 자체는 여전히 사용자가 업데이트 할 수 있습니다. 그런 경우, 기존 버전의 객체에 대한 미완성 된 작업은 결과가 오래되지 않았으므로 결과를 폐기해야합니다. 이것은 또한 원자 SQL 업데이트를 사용하여 쉽게 수행 할 수 있습니다.

UPDATE objects SET results = '...' WHERE id = 1234 AND version = 1

객체가 업데이트되면 해당 버전이 일치하지 않으므로 결과가 폐기됩니다.

이 두 원자 업데이트는 가능한 모든 레이스 조건을 처리해야합니다. 문제는 단위 테스트에서이를 확인하는 방법입니다.

첫 번째 세마포어는 테스트하기 쉽습니다. 단순히 두 가지 가능한 시나리오로 두 가지 다른 테스트를 설정하는 문제입니다. (데이터베이스 공급 업체의 책임이어야하기 때문에 SQL 쿼리의 원자력을 테스트 할 필요가 없습니다.)

두 번째 세마포어를 어떻게 테스트합니까? 첫 번째 세마포어 이후에 제 3자가 제 3자가 바꾸어야합니다. 이를 위해서는 업데이트가 안정적이고 일관되게 수행 될 수 있도록 실행중인 일시 정지가 필요하지만 RSPEC로 중단 점을 주입하는 데 대한 지원은 없다. 이것을 할 방법이 있습니까? 아니면 그러한 레이스 조건을 시뮬레이션하기 위해 간과하고있는 다른 기술이 있습니까?

도움이 되었습니까?

해결책

전자 제품 제조에서 아이디어를 빌려서 테스트 후크를 생산 코드에 직접 넣을 수 있습니다. 회로 보드를 테스트 장비를위한 특수 장소로 제어 할 수있는 것처럼 회로를 제어하고 조사 할 수있는 것처럼 코드와 동일한 작업을 수행 할 수 있습니다.

데이터베이스에 행을 삽입하는 코드가 있다고 가정합니다.

class TestSubject

  def insert_unless_exists
    if !row_exists?
      insert_row
    end
  end

end

그러나이 코드는 여러 컴퓨터에서 실행 중입니다. 그러면 다른 프로세스가 테스트와 삽입 사이에 행을 삽입 할 수 있으므로 레이스 조건이 있습니다. 우리는 코드가 해당 레이스 조건의 결과로 인한 예외를 처리하는 것을 테스트하고자합니다. 이를 위해서는 테스트가 호출 후 행을 삽입해야합니다. row_exists? 그러나 전화하기 전에 insert_row. 그럼 바로 테스트 후크를 추가해 봅시다.

class TestSubject

  def insert_unless_exists
    if !row_exists?
      before_insert_row_hook
      insert_row
    end
  end

  def before_insert_row_hook
  end

end

야생에서 달리면 고리는 약간의 CPU 시간을 먹는 것 외에는 아무것도하지 않습니다. 그러나 코드가 레이스 조건에 대해 테스트 될 때 테스트 원숭이 패치 이전 _insert_row_hook :

class TestSubject
  def before_insert_row_hook
    insert_row
  end
end

교활하지 않습니까? 의심의 여지가없는 애벌레의 본체를 납치 한 기생성 말벌 유충처럼 테스트는 테스트중인 코드를 납치하여 테스트 해야하는 정확한 조건을 만들 수 있습니다.

이 아이디어는 XOR 커서만큼 간단하므로 많은 프로그래머가 독립적으로 발명했다고 생각합니다. 경주 조건으로 코드를 테스트하는 데 일반적으로 유용하다는 것을 알았습니다. 도움이되기를 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top