2015-01-06 3 views
6

BlueJ의 JUnit을 사용하여 GiftSelector 클래스의 테스트 클래스를 작성하고 있습니다.왜 프로그램이 실행될 때만 가끔 나타나는 NPE를 얻고 있습니까?

assertEquals(true, santasSelector.getCountsForAllPresents().get(banana) == 3); 

이 NPE에 대한 이상한 것은, 내가 한 번 테스트를 실행할 때 거의 나타나지 않는 것입니다,하지만 자주는 실행 두 번째로 나타납니다 : 나는 testGetCountForAllPresents() 방법을 실행하면, 나는 라인에 NullPointerException를 얻을 수 테스트. 테스트를 7-8 번 연속 실행할 때까지는 때때로 나타나지 않습니다.

내가받는 오류 메시지는 다음과 같습니다. 예외 메시지가 없습니다. 내 테스트 클래스에 대한 GiftSelectortest.testGetCountForAllPresents

코드 라인 (215)에

NPE이다 : 나는 getCountsForAllPresents() 방법을 참조만을 시험 방법을 포함 시켰습니다

import static org.junit.Assert.*; 
import org.junit.After; 
import org.junit.Before; 
import org.junit.Test; 

/** 
* The test class GiftSelectorTest. The GiftSelector that you are 
* testing must have testMode enabled for this class to function. 
* This is done in the setUp() method. 
*/ 
public class GiftSelectorTest 
{ 
    private GiftList giftList1; 
    private GiftList giftList2; 
    private GiftList giftList3; 
    private Child jack; 
    private Child bob; 
    private Child dave; 
    private Child naughty1; 
    private GiftSelector santasSelector; 
    private Present banana1; 
    private Present orange; 
    private Present banana; 
    private Present apple; 
    private Present bike; 
    private Present doll; 
    private Present got; 
    private Present pearlHarbour; 
    private Present dog; 
    private Present cat; 
    private Present ball; 
    private Present heineken; 

    /** 
    * Default constructor for test class GiftSelectorTest 
    */ 
    public GiftSelectorTest() 
    { 
     //Nothing to do here... 
    } 

    /** 
    * Sets up the test fixture. 
    * 
    * Called before every test case method. 
    */ 
    @Before 
    public void setUp() 
    { 
     santasSelector = new GiftSelector(); 
     santasSelector.setTestMode(true); 
     jack = new Child("Jack", 20, "1 A Place", true, true, true, false); 
     bob = new Child("Bob", 10, "2 A Place", true, true, true, true); 
     dave = new Child("Dave", 10, "3 A Place", true, true, true, true); 
     naughty1 = new Child("John", 5, "4 A Place", true, true, true, true); 
     giftList1 = new GiftList(jack); 
     giftList2 = new GiftList(bob); 
     giftList3 = new GiftList(dave); 
     banana = new Present("banana", "fruit", 10); 
     orange = new Present("orange", "fruit", 10); 
     banana1 = new Present("banana", "fruit", 10); 
     apple = new Present("apple", "fruit", 10); 
     bike = new Present("bike", "toy", 200); 
     doll = new Present("doll", "toy", 40); 
     got = new Present("game of thrones", "dvd", 50); 
     pearlHarbour = new Present("pearl harbour", "dvd", 20); 
     dog = new Present("dog", "animal", 100); 
     cat = new Present("cat", "animal", 80); 
     ball = new Present("ball", "toy", 5); 
     heineken = new Present("heineken", "beer", 1.60); 
    } 

    /** 
    * Tears down the test fixture. 
    * 
    * Called after every test case method. 
    */ 
    @After 
    public void tearDown() 
    { 
     //Nothing to do here... 
    } 


    @Test 
    public void testGetCountForAllPresents() 
    { 
     System.out.println(santasSelector.getCountsForAllPresents()); 
     //Test on empty GiftSelector 
     assertNull(santasSelector.getCountsForAllPresents()); 

     //Test on a GiftSelector with one giftlist containing one present 
     giftList1.addPresent(banana); 
     santasSelector.addGiftList(giftList1); 
     System.out.println(santasSelector.getCountsForAllPresents()); 
     assertEquals(true, santasSelector.getCountsForAllPresents().get(banana) == 1); 

     //Test when GiftSelector contains 2 giftlists, each containing the same present object 

     giftList2.addPresent(banana); 
     santasSelector.addGiftList(giftList2); 
     System.out.println(santasSelector.getCountsForAllPresents()); 
     assertEquals(true, santasSelector.getCountsForAllPresents().get(banana) == 2); 

     //Test when GiftSelector contains 3 giftlists, 2 containing the same present object and another containing an identical present but with a different present instance 
     giftList3.addPresent(banana1); 
     santasSelector.addGiftList(giftList3); 
     System.out.println(santasSelector.getCountsForAllPresents()); 
     assertEquals(true, santasSelector.getCountsForAllPresents().get(banana) == 3); //This is the line I get the NPE 

     //Test when GiftSelector contains 3 giftLists, the first with one with a banana, the second with a banana and apple, and the third with a banana1 and ball 
     giftList2.addPresent(apple); 
     giftList3.addPresent(ball); 
     System.out.println(santasSelector.getCountsForAllPresents()); 
     assertEquals(true, santasSelector.getCountsForAllPresents().get(banana) == 3); 
     assertEquals(true, santasSelector.getCountsForAllPresents().get(apple) == 1); 
     assertEquals(true, santasSelector.getCountsForAllPresents().get(ball) == 1); 

    } 


    @Test 
    public void testGetMostPopularPresent() 
    { 
     //Test on empty GiftSelector 
     assertNull(santasSelector.getMostPopularPresent()); 

     //Test on a GiftSelector with one giftList and one Present 
     giftList1.addPresent(heineken); 
     santasSelector.addGiftList(giftList1); 
     assertEquals(true, santasSelector.getMostPopularPresent().comparePresent(heineken)); 

     //Tset on a GiftSelector with 1 giftList and 2 presents, one more expensive than the other 
     giftList1.addPresent(banana); 
     assertEquals(true, santasSelector.getMostPopularPresent().comparePresent(banana)); 

     //Test on a GiftSelector with 1 giftList and 3 presents. Banana and Apple are equal in price, and are both in the top3, 
     //therefore it should return the present closest to the start of the list 
     giftList1.addPresent(apple); 
     assertEquals(true, santasSelector.getMostPopularPresent().comparePresent(banana) || santasSelector.getMostPopularPresent().comparePresent(apple)); 

     //Test on a GiftSelector with 2 giftLists, the second list containing banana1, an indentical present to banana 
     giftList2.addPresent(banana1); 
     santasSelector.addGiftList(giftList2); 
     assertEquals(true, santasSelector.getMostPopularPresent().comparePresent(banana)); 

     //Test on a GiftSelector with 2 giftLists, the first containing four presents and the second containing 2 presents. 
     //This tests to see if top3 is working. 
     giftList1.addPresent(bike); 
     giftList2.addPresent(bike); 
     assertEquals(true, santasSelector.getMostPopularPresent().comparePresent(bike)); 
    } 
} 

. getCountForAllPresents() 메서드를 포함하는 assertEquals() 메서드를 호출하기 전에 print 문을 추가 한 것을 알 수 있습니다. 흥미로운 점은 NPE를 얻는 라인 이전에 print 문이 HashMap에 대한 올바른 값인 getCountForAllPresents()을 반환한다는 것입니다. 내가 눈치 챘을

유일한 다른 이상한 것은이라고 내가 사용하는 testGetCountForAllPresents() 방법으로 갈 때 BlueJ의의 디버거를 내장, 나는 giftList3santasSelectorsantaMapHashMap에 나타납니다, 아직 인쇄 문을 계속하지 않는 것을 알 수 올바른 계산을 인쇄합니다. 이는 giftList3에 대해 알아야 함을 암시합니다. getCountForAllPresents()에 대한

코드는 다음과 같습니다

/** 
* For each present, calculate the total number of children who have asked for that present. 
* 
* @return - a Map where Present objects are the keys and Integers (number of children requesting 
* a particular present) are the values. Returns null if santaMap is empty. 
*/ 
public HashMap<Present, Integer> getCountsForAllPresents() 
{ 
    if(!santaMap.isEmpty()) { 
     //This HashMap contains a mapping from each unique real world present, represented by it's toComparisonString(), to a Present object representing it 
     HashMap<String, Present> uniquePresents = new HashMap<String, Present>(); 
     //This HashMap contains a mapping from each Present object in uniquePresents to the number of times it's toComparisonString() is equal to another in santaMap 
     HashMap<Present, Integer> presentFrequency = new HashMap<Present, Integer>(); 

     for(GiftList wishlist: santaMap.values()) { 
      for(Present present: wishlist.getAllPresents()) { 
       //Have we already seen this present? 
       if(uniquePresents.containsKey(present.toComparisonString())) { 
        //If so, update the count in presentFrequency 
        Integer tmp = presentFrequency.get(uniquePresents.get(present.toComparisonString())); 
        tmp++; 
        presentFrequency.put(uniquePresents.get(present.toComparisonString()), tmp); 
       } else { 
        //If not, add it to the maps uniquePresents and presentFrequency (with a frequency of 1) 
        uniquePresents.put(present.toComparisonString(), present); 
        presentFrequency.put(present, 1); 
       } 
      } 
     } 
     //Return a map with unique presents as keys and their frequencies as values 
     return presentFrequency; 
    } 
    else { 
     //If there are no mappings in Santa's map, return null 
     return null; 
    } 
} 

나는 santaMap 키와 같은 Child 객체와 값으로 GiftList 목적과 더불어, HashMap 것을 설명해야한다. 기본적으로 아이를 크리스마스 위시리스트에 매핑합니다. santaMap에는 동일한 아이가 한 개의 위시리스트 만 포함 할 수 있습니다.

내가 왜 NPE를 얻는 지 잘 모르겠다. 내가 getCountForAllPresents() 방법을 작성한 방법과 관련이 있습니까? 테스트 메소드/클래스를 어떻게 구현 했습니까?

+0

'현재'에 대한 코드를 추가 할 수 있습니까? – RealSkeptic

+1

라인 215는 어디에서 null이됩니까? –

+0

'GiftSelector'의 전체 코드가 더해 졌다고 생각합니다. –

답변

4

Present 클래스는 hashCode()equals()을 덮어 쓰지 않습니다. 즉 banana1banana은 키로 사용할 HashMap에서 두 개의 고유 키입니다.

여기에서 어떤 현상이 발생하는지 봅시다. bananabanana1 개체가 있습니다. 두 개체는 첫 번째 인스턴스와 두 번째 인스턴스 중 하나입니다.

getCountsForAllPresents() 내부에는 두 개의 해시지도가 있습니다. 첫 번째는 객체의 비교 문자열로 이동하고 두 번째는 객체 자체로 이동합니다.

처음 만나는 바나나를 추가합니다.

uniquePresents 
banana-fruit-10 ➞ [banana instance] 

presentFrequency 
[banana instance] ➞ Integer(1) 

당신은 반복을 계속 : 그것은 banana 객체 인 경우, 다음과 같이해야합니다. 다음 banana 개체가 있습니다. 그것은 같은 대상입니다. 다음과 같이 표시됩니다.

uniquePresents 
banana-fruit-10 ➞ [banana instance] 

presentFrequency 
[banana instance] ➞ Integer(2) 

이제 banana1 개체가 표시됩니다. 그것은 다른 객체이지만, 비교 문자열은 같습니다! 무슨 일이야?

이 조건은 참입니다 : uniquePresents.containsKey(present.toComparisonString()). 이것은 그것이 if의 진실한 부분으로 들어가는 것을 의미합니다.

Integer tmp = presentFrequency.get(uniquePresents.get(present.toComparisonString())); 

이는 banana 목적은 현재 banana-fruit-10가 가리키는 객체 취할 것을 의미합니다 -하지 banana1 객체를 관련 주파수를 얻고, 그것을 증가. 또한 동일한 객체로 저장됩니다. 당신이 지금 가지고있는 것은 모든에서 banana1 키가없는

uniquePresents 
banana-fruit-10 ➞ [banana instance] 

presentFrequency 
[banana instance] ➞ Integer(3) 

presentFrequency있다. 이제이 객체를 반환합니다.

banana까지 검색하려고하면 정상적으로 작동하며 어설 션이 작동합니다.

하지만 santaMapHashMap입니다. 즉, 보증 된 주문이 없음을 의미합니다. 이터레이터는 giftList1, giftList2, giftList3을 줄 수도 있지만 giftList3, giftList1, giftList2 또는 다른 순서로 줄 수도 있습니다.

그럼 먼저 giftList3을 주면 어떻게됩니까? 당신이 끝낼거야 :

uniquePresents 
banana-fruit-10 ➞ [banana1 instance] 

presentFrequency 
[banana1 instance] ➞ Integer(3) 

왜? banana1banana-fruit-10 키가있는 첫 번째 선물 이었으므로 앞으로 사용하게 될 것입니다.

이렇게 될 경우 banana을 반환 된 개체에서 가져 오려고하면 해당 키가 빈도 목록에 없습니다. null을 반환하며 사용자의 NullPointerException이 있습니다.

+0

이것을 아주 자세히 설명해 주셔서 감사합니다. 이를 수정하여 항상 올바른 답을 반환하도록하는 방법이 있습니까? 상당히 프로그래밍에 익숙하지 않기 때문에 메서드 오버라이드 및 기타 OO 기능을 아직 다루지 않았습니다. 현재의 hashCode() 및 Equals()를 재정의하는 것보다 나은 솔루션이 있습니까? – JC2188

+0

해시 맵에서 이러한 개체를 키로 사용하려는 것은 아닙니다. 그러나 해시 맵 (비교 문자열에 의해 키잉 됨)을 포함하는 객체와 같은 다른 것을 사용할 수 있으며'Present' 객체를 매개 변수로 사용하는'get' 메소드가 있으며 내부 해시 맵에서 빈도를 반환합니다 그것의 비교 문자열에 의해. 그런 다음 해당 객체를'getCountsForAllPresents()'의 반환 유형으로 사용하십시오. – RealSkeptic