我正在使用 BlueJ 中的 JUnit 为我的 GiftSelector 类编写测试类。当我运行 testGetCountForAllPresents() 方法时,我在该行收到了一个 NullPointerException:
assertEquals(true, santasSelector.getCountsForAllPresents().get(banana) == 3);
这个NPE奇怪的是,我跑一次测试的时候很少出现,第二次跑的时候经常出现。有时直到我连续运行测试 7-8 次后才会出现。
我得到的错误信息是: 没有异常消息。
NPE at line 215 in GiftSelectortest.testGetCountForAllPresents
我的测试类的代码是:
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));
}
}
我只包含了引用 getCountsForAllPresents() 方法的测试方法。您会注意到,我在每次调用包含 getCountForAllPresents() 方法的 assertEquals() 方法之前添加了打印语句。有趣的是,在我获得 NPE 的那一行之前,print 语句打印出 getCountForAllPresents() 返回的 HashMap 的正确值。
我注意到的另一件奇怪的事情是,当我使用 BlueJ 的内置调试器执行 testGetCountForAllPresents() 方法时,我注意到 giftList3 没有没有出现在 santasSelector 的 santaMap HashMap 中,但是打印语句仍然打印正确的计数,这意味着它必须知道 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 是一个 HashMap,以 Child 对象作为键和一个 GiftList 对象作为值(value)。它基本上将 child 映射到他们的圣诞愿望 list 。 santaMap 只能包含同一个 child 的一个心愿单。
我不知道为什么我会收到 NPE,这与我编写 getCountForAllPresents() 方法的方式有关吗?我是如何实现测试方法/类的?
最佳答案
您的 Present 类不会覆盖 hashCode() 和 equals()。这意味着 banana1 和 banana 在任何将使用它们作为键的 HashMap 中都是两个不同的键。
让我们看看这里发生了什么。您有 banana 和 banana1 对象 - 第一个对象中的两个,第二个对象中的一个。
在 getCountsForAllPresents() 中,您有两个 HashMap 。第一个通过对象的比较字符串,第二个通过对象本身。
您添加遇到的第一根香蕉。如果它是 banana 对象,您将得到如下内容:
uniquePresents banana-fruit-10 ➞ [banana instance] presentFrequency [banana instance] ➞ Integer(1)
You continue to iterate. You encounter the next banana object. It's the same object. You'll get:
uniquePresents banana-fruit-10 ➞ [banana instance] presentFrequency [banana instance] ➞ Integer(2)
Now you get to the banana1 object. It's a different object, but it has the same comparison string! What happens?
This condition is true: uniquePresents.containsKey(present.toComparisonString()). This means it goes into the true part of the if.
Integer tmp = presentFrequency.get(uniquePresents.get(present.toComparisonString()));
这意味着它将获取当前由 banana-fruit-10 指向的对象,即 banana 对象 - 而不是 banana1 对象,获取其关联的频率,并递增它。它也由同一个对象存储。你现在拥有的是:
uniquePresents banana-fruit-10 ➞ [banana instance] presentFrequency [banana instance] ➞ Integer(3)
请注意,presentFrequency 根本没有 banana1 键。现在你返回这个对象。
当您尝试通过 banana 检索时,它工作正常 - 断言工作。
但请记住,santaMap 本身就是一个HashMap。这意味着没有保证订单。迭代器可能会给你giftList1,giftList2,giftList3,但它也可能给你giftList3, giftList1、giftList2 - 或任何其他订单。
那么当它首先给你 giftList3 时会发生什么?你最终会得到:
uniquePresents banana-fruit-10 ➞ [banana1 instance] presentFrequency [banana1 instance] ➞ Integer(3)
为什么?因为 banana1 是第一个带有 key banana-fruit-10 的礼物,从现在开始它将使用它。
发生这种情况时,当您尝试从返回的对象中获取 banana 时,该键不存在于频率列表中。它返回 null - 并且存在您的 NullPointerException。
关于java - 为什么我的 NPE 只是在程序运行时偶尔出现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27804652/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
我想用ruby编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r