2017-01-10 2 views
-1

내가 코 틀린 실제로 무엇을하고 있는지 이해하는 데 문제가 있어요 덮어 쓰기 :코 틀린 : 슈퍼 생성자에서 변경이

내 단위 테스트는 다음과 같습니다

:

내 파서가이

abstract class EnvelopeParser(val xml: String) { 
    abstract fun parseResponse(response: Element) 

    init { 
     parseResponse(xmlFromString(xml)) 
    } 

    // non-related stuff 
} 
과 같은
@Test 
fun testReadCursorRequest() { 
    val xml = fromFile() 
    val parser: ReadCursorRequestParser = ReadCursorRequestParser(xml) 
    assertEquals(0, parser.status) 
    assertEquals(134, parser.contacts!!.size) 
} 

class ReadCursorRequestParser(xml: String) : EnvelopeParser(xml) { 

    var contacts: List<AddressBookElementParser> = mutableListOf()  

    override fun parseResponse(response: Element) { 
     // here some parsing stuff, fills the contacts-list 
     println("size is: ${contacts.size}") 
    } 
} 

println은 size is: 134라고 말하면 단위 테스트 결과는 java.lang.AssertionError: Expected <134>, actual <0>입니다.

왜?

+0

구문 분석 작업 내에서'contacts'라는 로컬 변수가 있습니까? 만약 있다면, 속성에 저장된'contacts'의 크기가 아닌 크기가 출력됩니다. – hotkey

+2

또한, 당신의 테스트는'parseResponse()'를 호출하는 것 같지 않습니다. 그걸 어디에서 부르니? – hotkey

+0

이 항목에서 건너 뛰었던 항목으로 인해 이것이 분명하지 않은 경우 유감스럽게 생각합니다. 가능한 한 짧고 상황에 맞는 내용을 유지하려고했습니다. EnvelopeParser는 실제로 생성자에서 parseResponse를 호출합니다. 실제로 디버깅 모드에서 중단 점을 실행하므로 로컬 변수 연락처가 100 % 확실하며 IntelliJ는 println에서 중단 될 때 연락처 멤버의 값을 렌더링합니다. –

답변

5

의견에서 언급했듯이 parseResponse(...)EnvelopeParser 생성자 내부에서 호출됩니다.

그런 다음 ReadCursorRequestParser의 인스턴스를 만들 때 무슨 일이 일어나고 있는지입니다 :

  1. 객체가 할당됩니다.

  2. ReadCursorRequestParser 생성자가 호출되고 바로 수퍼 클래스 생성자를 호출합니다.

  3. 슈퍼 생성자 (EnvelopeParser)는 parseResponse(...)을 호출하므로 contacts이 할당됩니다 (실제로는 비어 있지 않은 목록입니다).

  4. 슈퍼 생성자가 반환되고 ReadCursorRequestParser의 생성자가 계속됩니다.

  5. ReadCursorRequestParser 생성자는 지금은 빈리스트이다, 다시 contacts을 할당합니다.

그 이유는 각각의 생성자는 먼저 수퍼 생성자를 호출 (있는 경우) 오직 그 특성을 초기화하고 init 블록을 실행하고 superconstructor와이 상태로 변경된 모든 클래스에 선언이다 (기본 클래스가 아닌) 클래스 자체 생성자가 겹쳐 씁니다.

이 간단한 예제는이 동작을 보여줍니다. (link).


가장 쉬운 해결 방법은이 선언으로

lateinit var contacts: List<AddressBookElementParser> 

처럼 뭔가 contacts의 선언을 변경하는 것입니다, 생성자는 contacts를 다시 할당하지 않습니다.

그러나, 오버라이드 (override)하는 경우, 그들은 (일반적으로 할) 수 있습니다 아직 초기화되지 않은 파생 클래스 상태에 의존하기 때문에 오히려 강력하게 생성자에서 open 함수를 호출하지 않도록 할 것을 권 해드립니다, 또한 변경된 은 파생 클래스 생성자에 의해을 덮어 씁니다. 수퍼 클래스 상태로 완료되고 다른 부분이 지워지므로 변경 사항의 일부가 영구적으로 끝날 수도 있습니다. 일상 생활에서 보려고하는 것이 아닙니다.