2010-08-04 2 views
9

ScalaTest를 사용하여 스칼라로 작성한 파서를 테스트하고 있습니다. 파서는 한 번에 하나 개의 파일을 처리하고 그것은 다음과 같은 단일 개체가 있습니다ScalaTest : Singleton Object 재 초기화 문제

class Parser{...} 
object Resolver {...} 

내가 작성한 테스트 케이스는 이전의 부작용 반복 각 지금이

describe("Syntax:") { 
    val dir = new File("tests\\syntax"); 
    val files = dir.listFiles.filter(
        f => """.*\.chalice$""".r.findFirstIn(f.getName).isDefined); 

    for(inputFile <- files) { 
     val parser = new Parser(); 
     val c = Resolver.getClass.getConstructor(); 
     c.setAccessible(true); 
     c.newInstance(); 

     val iserror = errortest(inputFile) 
     val result = invokeparser(parser,inputFile.getAbsolutePath) //local method 
     it(inputFile.getName + (if (iserror)" ERR" else " NOERR")){ 
     if (!iserror) result should be (ResolverSuccess()) 
     else if(result.isInstanceOf[ResolverError]) assert(true) 
     } 
    } 
    } 

처럼 다소이다 싱글 톤 객체 Resolver 내부의 반복은 정리되지 않습니다.

싱글 톤 객체를 다시 초기화하기 위해 스 케일 테스트 모듈을 지정하는 방법이 있습니까?

업데이트 : 다니엘의 제안을 사용하여 코드를 업데이트했으며 자세한 내용도 추가했습니다.

업데이트 : 분명히 뭔가 비린내가있는 파서입니다. 후속 호출에서는 이전 AST를 삭제하지 않습니다. 이상한. 이것은 주제를 벗어난 것이기 때문에 더 많이 파고 토론을위한 별도의 스레드를 사용합니다. 답변을 주셔서 감사합니다.

최종 업데이트 :이 문제는 Resolver가 아닌 다른 싱글 톤 개체와 관련된 것이 었습니다 그래서 나는 그것을 어떻게 든 놓쳤다. Daniel Spiewak의 대답을 사용하여이 문제를 해결할 수있었습니다. 그것은 일을하는 더러운 방법이지만 그것도 내 상황을 감안할 때 유일한 것은, 또한 프로덕션 사용으로 가지 않을 테스트 코드를 작성하고 있다는 사실을 감안할 때.

+0

'R'안에 정리 방법이 있습니까? 아니면 다시 만들어지기를 기대합니까? –

+0

R에는 정리 방법이 없으므로 코드를 변경할 수 없습니다. 스칼라에서 싱글 톤 객체를 다시 만들 수 있습니까? – thequark

+0

아니요. 그들은 엄격하게 싱글 톤입니다. 주문형 (JVM의 클래스 로딩에 의해 결정됨) 이후에는 영원한 것으로 초기화됩니다. 물론 스칼라 클래스와 마찬가지로 가변적 인 내부 상태를 가질 수 있습니다. –

답변

7

언어 사양에 따르면 아니요, 싱글 톤 개체를 다시 만들 수있는 방법이 없습니다. 그러나, 는 반사적으로 실제 싱글 값이 들어있는 내부 MODULE$ 필드 덮어 싱글의 생성자 호출 수 있습니다 : 지금은 당신과 함께 악마의 비밀을 공유 한 것을

object Test 

Test.hashCode // => e.g. 779942019 

val c = Test.getClass.getConstructor() 
c.setAccessible(true) 
c.newInstance() 

Test.hashCode // => e.g. 1806030550 

을, 저를 보자 당신이 결코 이것을 할 수 없도록주의하시기 바랍니다. . 이 코드와 같은 비열한 트릭을 사용하는 것보다는 코드를 조정하는 것이 매우 어렵습니다. 그러나, 당신이 말한대로 일이 있고 다른 옵션이 없다면, 이것은 적어도 뭔가입니다.

+1

이런 식으로 싱글 톤 객체를 다시 초기화해도 문제는 계속됩니다. 나는 어떻게 해야할지 모르겠다. 기본적으로 각 입력 파일을 개별적으로 테스트하면 제대로 작동하지만 함께 테스트하면 오류가 발생합니다. 주문을 변경하면 오류도 발생합니다 (이전 테스트 사례와 관련된 오류 메시지가 표시됨). 싱글 톤 객체가 이전 반복의 부작용을 가지고 있기 때문에 그럴 수 있다고 생각됩니다. – thequark

+0

시도해 보았습니다 ... java.lang.NoSuchMethodException : com.whatever.SingletonObject $. () – jm0

+0

위의 @ daniel-spiewak 예제를 으로 변경해야했습니다. val c = Test.getClass.getDeclaredConstructor() –

4

ScalaTest에는 테스트간에 사물을 다시 초기화 할 수있는 몇 가지 방법이 있습니다. 그러나이 특별한 질문은 더 많이 알지 못하면 대답하기가 어렵습니다. 가장 큰 문제는 싱글 톤 객체를 다시 초기화하는 데 무엇이 필요합니까? 새 싱글 톤 객체를 인스턴스화하지 않고 싱글 톤 객체를 다시 초기화 할 수없는 경우 각 테스트가 새 싱글 톤 객체를 새로로드해야하므로 사용자 정의 클래스 로더를 사용해야합니다. 나는 누군가가 그런 식으로 뭔가를 디자인 할 것이라고 믿는 것이 어렵다고 느낍니다. 그런 세부 사항으로 질문을 업데이트 할 수 있습니까? 나중에 다시 살펴보고 추가 세부 정보로 대답을보다 분명하게 볼 수 있습니다.

ScalaTest에는 각 실행에 대해 클래스를 새로로드하지만 테스트 경로는 새로로드하지 않는 실행 경로가 있습니다. 그래서 당신은 당신 자신의 것을 굴려야 할 것입니다. 진짜 문제는 누군가가 쉽게 테스트 할 수없는 방식으로 이것을 설계했다는 것입니다. Resolver와 Parser를 URLClassLoader로로드 할 때마다 테스트 할 것입니다. 그렇게하면 각 리졸버가 각 테스트를 받게됩니다.

클래스 경로에서 파서 & 리졸버를 꺼내고 경로에서 벗어나야합니다. 그들을 자신의 디렉토리에 넣어 라. 그런 다음 해당 디렉토리를 가리키는 각 테스트에 대해 URLClassLoader를 만듭니다.그런 다음 해당 클래스 로더에서 findClass ("Parser")를 호출하여 가져옵니다. 나는 Parser가 Resolver를 가리키고 있다고 가정하고 있고,이 경우 JVM은 URLClassLoader 인 Resolver를 얻기 위해 Parser를로드 한 클래스 로더로 돌아갈 것이다. Parser로 newInstance를 실행 해 인스턴스를 취득합니다. 각 테스트에 대해 새로운 Resolver 싱글 톤 객체를 얻으므로 문제가 해결됩니다.

+0

새 파서를 만들면 싱글 톤 개체가 다시 초기화되지 않고 파서 개체가 루프 안에 생성됩니다 . (업데이트 된 코드 확인) 하나의 실행 추적에서 단일 입력 파일을 허용하도록 코드가 작성되었습니다. – thequark