最近做iFix GVT测试工作,要测试中文的mock(关于Mock Testing,见附1)
可以发现部署好mock的测试环境后,不管是用IE还是FF都无法打开UI,错误异常信息如下:
Error page exception
The server cannot use the error page specified for your application to handle the Original Exception printed below. Please see the Error Page Exception below for a description of the problem with the specified error page.
Original Exception:
Error Message: Can't find bundle for base name com.ibm.rfidic.messages.RFIDICUIMessages, locale
Error Code: 500
Target Servlet: /jsp/RFIDICLogin.jsp
Error Stack:
java.util.MissingResourceException: Can' |
Error page exception
The server cannot use the error page specified for your application to handle the Original Exception printed below. Please see the Error Page Exception below for a description of the problem with the specified error page.
Original Exception:
Error Message: Can't find bundle for base name com.ibm.rfidic.messages.RFIDICUIMessages, locale
Error Code: 500
Target Servlet: /jsp/RFIDICLogin.jsp
Error Stack:
java.util.MissingResourceException: Can't find bundle for base name com.ibm.rfidic.messages.RFIDICUIMessages, locale
at java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:853)
at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:743)
at java.util.ResourceBundle.getBundle(ResourceBundle.java:593)
at com.ibm.rfidic.utils.messages.impl.MessageProvider.getResourceBundle(MessageProvider.java:142)
at com.ibm.rfidic.utils.messages.impl.MessageProvider.getMessageString(MessageProvider.java:149)
at com.ibm.rfidic.utils.messages.impl.Message.getMessage(Message.java:87)
at com.ibm.rfidic.web.ui.admin.model.CommonGUIProvider.getMessage(CommonGUIProvider.java:545)
at com.ibm.rfidic.web.ui.admin.model.CommonGUIProvider.getMessageEscapedForHTML(CommonGUIProvider.java:492)
at com.ibm._jsp._RFIDICLogin._jspService(_RFIDICLogin.java:104)
at com.ibm.ws.jsp.runtime.HttpJspBase.service(HttpJspBase.java:87)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1146)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1087)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:145)
at com.ibm.rfidic.web.ui.admin.filters.ServletFilter.doFilter(ServletFilter.java:65)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:190)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:130)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain._doFilter(WebAppFilterChain.java:87)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:837)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:680)
at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:588)
at com.ibm.ws.wswebcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:481)
at com.ibm.wsspi.webcontainer.servlet.GenericServletWrapper.handleRequest(GenericServletWrapper.java:122)
at com.ibm.ws.jsp.webcontainerext.AbstractJSPExtensionServletWrapper.handleRequest(AbstractJSPExtensionServletWrapper.java:232)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3507)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:269)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:815)
at com.ibm.ws.wswebcontainer.WebContainer.handleRequest(WebContainer.java:1466)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:122)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:458)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:387)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.ready(HttpInboundLink.java:267)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:214)
at com.ibm.ws.tcp.channel.impl.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:113)
at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
at com.ibm.io.async.AsyncChannelFuture$1.run(AsyncChannelFuture.java:205)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)
问题解决:
原来是IE和FF默认的语言选择成了en_US,而不是zh_CN。
以FF为例,“工具” -> “选项” -> “内容” -> “语言” ,将浏览器的默认语言改成“中文”即可解决。
问题分析:
java.util.MissingResourceException: Can’t find bundle for base name com.ibm.rfidic.messages.RFIDICUIMessages, locale
注意到此错误信息,提示找不到Base的properties文件,并且locale是空值?
Base的properties文件RFIDICUIMessages确实不存在,因为在做Mock的时候已经将其改为RFIDICUIMessages_zh_CN.properties文件了,为什么系统不会自动去找zh_CN呢?
走近源代码观察:
public class MessageProvider implements IMessageProvider {
..... //省略其他方法与变量
private ResourceBundle getResourceBundle(Message message)
{
Locale locale = message.getLocale();
if (locale.getLanguage().equals("en")) { // 肯定是message的locale设为了en_US才会导致locale重置为空!!!继续查找其他locale设置的方法LocaleContext类,见下。
locale = new Locale("", "", "");
}
ResourceBundle resourceBundle = (this.loader != null) ?
ResourceBundle.getBundle(this.messageConstants.getResourceName(message.getId()), locale, this.loader) :
ResourceBundle.getBundle(this.messageConstants.getResourceName(message.getId()), locale);
return resourceBundle;
}
protected String getMessageString(Message message)
{
ResourceBundle resourceBundle = getResourceBundle(message);
return resourceBundle.getString(message.getMessageId());
}
public IMessage getMessage(int messageId, Object[] args)
{
return getMessage(messageId, LocaleContext.current().getLocale(), args);
} |
public class MessageProvider implements IMessageProvider {
..... //省略其他方法与变量
private ResourceBundle getResourceBundle(Message message)
{
Locale locale = message.getLocale();
if (locale.getLanguage().equals("en")) { // 肯定是message的locale设为了en_US才会导致locale重置为空!!!继续查找其他locale设置的方法LocaleContext类,见下。
locale = new Locale("", "", "");
}
ResourceBundle resourceBundle = (this.loader != null) ?
ResourceBundle.getBundle(this.messageConstants.getResourceName(message.getId()), locale, this.loader) :
ResourceBundle.getBundle(this.messageConstants.getResourceName(message.getId()), locale);
return resourceBundle;
}
protected String getMessageString(Message message)
{
ResourceBundle resourceBundle = getResourceBundle(message);
return resourceBundle.getString(message.getMessageId());
}
public IMessage getMessage(int messageId, Object[] args)
{
return getMessage(messageId, LocaleContext.current().getLocale(), args);
}
public class LocaleContext
{
private Locale locale;
private TimeZone timeZone;
private static ThreadLocal currentPreference = new ThreadLocal();
public LocaleContext()
{
this(Locale.getDefault(), TimeZone.getDefault());
}
public LocaleContext(Locale locale, TimeZone timeZone)
{
this.locale = locale;
this.timeZone = timeZone;
}
public Locale getLocale()
{
return this.locale;
}
public TimeZone getTimeZone()
{
return this.timeZone;
}
public void reset()
{
this.locale = Locale.US;
this.timeZone = TimeZone.getDefault();
}
public void setLocale(Locale locale)
{
this.locale = locale;
}
public void setTimeZone(TimeZone zone)
{
this.timeZone = zone;
}
public static LocaleContext current()
{
LocaleContext localeContext = (LocaleContext)currentPreference.get();
if (localeContext == null)
{
localeContext = new LocaleContext();
bind(localeContext);
}
return localeContext;
}
public static void bind(LocaleContext localeContext)
{
currentPreference.set(localeContext);
}
public static void unbind()
{
currentPreference.set(null);
}
} |
public class LocaleContext
{
private Locale locale;
private TimeZone timeZone;
private static ThreadLocal currentPreference = new ThreadLocal();
public LocaleContext()
{
this(Locale.getDefault(), TimeZone.getDefault());
}
public LocaleContext(Locale locale, TimeZone timeZone)
{
this.locale = locale;
this.timeZone = timeZone;
}
public Locale getLocale()
{
return this.locale;
}
public TimeZone getTimeZone()
{
return this.timeZone;
}
public void reset()
{
this.locale = Locale.US;
this.timeZone = TimeZone.getDefault();
}
public void setLocale(Locale locale)
{
this.locale = locale;
}
public void setTimeZone(TimeZone zone)
{
this.timeZone = zone;
}
public static LocaleContext current()
{
LocaleContext localeContext = (LocaleContext)currentPreference.get();
if (localeContext == null)
{
localeContext = new LocaleContext();
bind(localeContext);
}
return localeContext;
}
public static void bind(LocaleContext localeContext)
{
currentPreference.set(localeContext);
}
public static void unbind()
{
currentPreference.set(null);
}
}
问题就在于浏览器发送的HTTP请求locale是en_US的,到了服务器端自动找默认的RFIDICUIMessages(不带任何后缀),发现没有此resource才抛错。
另外以此可以推断原来访问Google.com的规则,如果浏览器默认设置为中文,那么服务器端会判断时区然后自动重定向到Google.cn;相反如果浏览器设置为英文en_US,那么就是在访问Google.com
附1:Mock Testing简介
Mock Testing又叫做pseudo translation testing
1.检查点
1)检查text是否作了pseudo translated (即,是否做了mock. 主要是检查text是否被抽取从来到resource 文件)
2)检查text是否有concatenated(拼接,嵌套)的情况Example: [text] [other text] (拼接)Example: [I go to the [store]] (嵌套)一个句子不可以分为两条message. 如上面的example1。除非是有句号,问号等,标示是两个不同的句子。
3)检查text是否被corrupted(截断)
例如 text 在英文下是: sample messages
在做了mock以后是, [zh中国~~sample mes
则是message 被截断了。 这一般是由于developers给该message留的space不够长。
4)检查是否有Garbled Characters (即显示不正常的字符)例如: 做了mock 的message是:[zh中国~~sample messages ~~ CN]
但是在UI上’中国’这两个字显示的是乱码,或者问号,或者方框。这可能是由于被测产品对相应的字符不支持。
5)检查UI 的控件的显示是否正常例如一:这个控件显示不全
2.Pseudo Translation Testing Process 测试流程
1)安装做过pseudo translated 的build. (在我们的rfidic,因为主要的pII file 是一些properties 文件,RFIDICInternalMessages.properties, RFIDICIWEMessages.properties, RFIDICUIMessages.properties 。 这些文件在com.ibm.rfidic.messages.jar文件中。我们的做法是把这些文件取出来,作mock translation, 然后再打回这个jar 文件去,直接把新jar文件copy到server 的相应目录。)
2)把系统的locale切换为需要测试的locale
For RHEL:
查找
[root@localhost ~]# locale
[root@localhost ~]# locale -a |grep jp ((UNIX)grep:字符串查找)
设置
[root@localhost ~]# export LANG=ja_JP.utf8
[root@localhost ~]# export LC_ALL= ja_JP.utf8
For Linux RedHat server, the following steps are for setting locale to Ja_JP.utf-8.
(1) vi /etc/sysconfig/i18n
(2) modify the LANG=”ja_JP.UTF-8″
(3) reboot server
For AIX:
(1) Edit /etc/environment
(2) 修改 LANG=locale ,export LANG.locale 是你要修改的具体locale.
(3) 保存然后 reboot
3)开始测试(text, message, tips, controls,…)