一个好的编写程序的习惯,每写一小段代码(比如一个方法或者更小)测试一下的他的正确性。倘若等到所有代码都写完了再去测试的话,那么等待你的将是无尽的烦恼与纠结。
  在GAE项目之中,按照以往的习惯引入Junit jar文件,新建test源码目录,新建测试用例,执行。可是预想之中的结果却没有出现,出现的反而是一个令人郁闷的异常。java.lang.NullPointerException: No API environment is registered for this thread.虽然本人也不喜欢看异常,但还是要硬着头皮把它看完。它说“没有API环境被注册到当前线程”。什么意思?似乎是缺少单元测试运行时的环境。看来只能使用原始的方法了。新建main方法并执行。Oh,my god!竟然还是这个异常。这到底是怎么回事儿?
  将单元测试中代码全部注释掉,执行。没有异常,执行正常。于是乎一点点的排查,终于发现只要用到gae数据操作会出现这个异常。看来问题是出在了gae的数据操作上。想了想,觉得可能是如下的原因:
  GAE 所提供的只是数据实体及其以上的操作,而再往下的底层物理数据操作是不对应用程序开放的,这些操作是有GAE平台去完成的。这好像是用JPA去访问数据库,可是光有实体类而没有数据库一样。因为数据库再别人得服务器上,而且你不能直接连接到数据库。
  而现在这个“数据库”(gae使用的不一定是数据库)是在GAE的服务器上。显然,GAE作为一个又不少开发者使用的平台不可能会考虑不到这种情况。而程序直接本地运行没有出问题更说明了这一点。说明了是可以在本地去模拟服务端的“数据库”以及“数据库”的底层操作的。下面要做的是……
  翻gae文档,终于在一个不起眼的地方找到了有关gae单元测试环境搭建的说明。上面说需要将额外的几个包引入到当前项目中。这几个包如下:
  ${SDK_ROOT}/lib/impl/appengine-api.jar
  ${SDK_ROOT}/lib/impl/appengine-api-labs.jar
  ${SDK_ROOT}/lib/impl/appengine-api-stubs.jar
  ${SDK_ROOT}/lib/testing/appengine-testing.jar
  前面的${SDK_ROOT}表示GAE SDK的更目录。导入之后竟然还需要手动的去加载这些环境,好在不是很复杂.需要在每个测试类中加入如下代码:
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
@Before
public void setUp() {
helper.setUp();
}
@After
public void tearDown() {
helper.tearDown();
}
  从类名可以看出来是要加载本地测试配置。现在再执行一遍,终于通过了。可是如果在每个测试类里面都要写上这么一些一模一样代码,每个人都不会愿意的。所以可以新建一个GAE单元测试基类,然后让所有的gae单元测试类都继承这个基类可以省掉这些麻烦了。
  另外,单元测试的数据都是临时产生的。每个测试方法执行前都要先插入数据。测试方法执行完成后,数据会自动被清空。