【问题标题】:Event based testing for android基于事件的android测试
【发布时间】:2011-08-17 07:42:50
【问题描述】:

我正在使用 robotsium 进行测试,但遇到了一堆时间问题,这让我很难知道活动(或视图)何时完成加载。因此,我正在编写的测试不是很健壮。

我正在寻找一种方法来使用可以推送到测试框架的事件来检测我的被测应用程序。如果我正在测试的应用程序可以在发生预期事件时“告诉”我的测试,这将非常有用。我以前在 windows\windows 手机上使用过Event Tracing for Windows,效果很好。

我正在研究的糟糕的方法是让我的测试应用程序实时读取 logcat 并在发生预期事件时通知测试。

还有人有其他想法吗?

【问题讨论】:

    标签: android testing robotium etw


    【解决方案1】:

    为了解决这个问题,我依赖于 OS logcat。我使用跟踪消息检测正在测试的代码部分,并等待它们出现在测试代码中。它可能不是最高效的做事方式,但它适合我的需要。我首先尝试创建一个从 logcat 读取的异步任务,但遇到了时间问题。我终于实现了这样的东西:

        logger.info("Click on something");
        EmSingleton.get().setCheckPoint();
        solo.clickOnText(SOMETHING, 1, true); // writes RELOAD_COMPLETE to logcat when done
    
        logger.info("Validate that the event is done);
        EmSingleton.get().waitForEvent(GrouponLnConstants.TodaysDeal.RELOAD_COMPLETE, 15000);
        // Do other stuff... 
    

    EventManager 代码(我包装在一个名为 EmSingleton 的单例中):

    public class EventManager {
    private ArrayList<String> args = null;
    private long startTime;
    
    public EventManager() {
        args = new ArrayList<String>(Arrays.asList("-v", "time", "-d"));
        setCheckPoint();
    }
    
    public EventManager(ArrayList<String> _args) {
        this();
        for(String s: args) {
            if (!args.contains(s)) {
                args.add(s);
            }
        }
    }
    
    public void setCheckPoint()
    {
        Time startTimeOS = new android.text.format.Time();
        startTimeOS.setToNow();
        startTime = startTimeOS.toMillis(true);
    }
    
    public LogEvent checkEvent(String filter) throws Exception {
        ArrayList<LogEvent> events = gatherEvents();
    
        for(LogEvent event: events){
            if(event.checkMsgSubstring(filter)){
                return event;
            }
        }
    
        return null;
    }
    
    public LogEvent waitForEvent(String filter, int timeout) throws Exception
    {
        int retries = timeout/1000 == 0 ? 1 : timeout/1000;
        for(int i = 0; i < retries; i++)
        {
            LogEvent event = checkEvent(filter);
            if(event != null){
                return event;
            }
            Thread.sleep(1000);
        }
        return null;
    }
    
    public ArrayList<LogEvent> getEvents() {
        return gatherEvents();
    }
    
    public void clearEvents() throws Exception{
        ArrayList<String> commandLine = new ArrayList<String>();
        commandLine.add("logcat");
        commandLine.add("-c");
    
        ProcessBuilder pb = new ProcessBuilder(commandLine.toArray(new String[0]));
        pb.redirectErrorStream(true);
        Process logcatProcess = pb.start();
    
        logcatProcess.waitFor();
    }
    
    protected ArrayList<LogEvent> gatherEvents() {
        ArrayList<LogEvent> events = new ArrayList<LogEvent>();
        final StringBuilder log = new StringBuilder();
        BufferedReader br;
        try {
            ArrayList<String> commandLine = new ArrayList<String>();
            commandLine.add("logcat");
            if (null != args) {
                commandLine.addAll(args);
            }
    
            ProcessBuilder pb = new ProcessBuilder(commandLine.toArray(new String[0]));
            pb.redirectErrorStream(true);
            Process logcatProcess = pb.start();
    
            InputStream is = logcatProcess.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
    
            String line = null;
    
            while (true) {
                line = br.readLine();
                if(line == null){
                    break;
                }
                // Add events to the events arraylist if they occur after the LogCollector has started to run
                LogEvent event = new LogEvent(line);
                if(event.peekTimeMS() > startTime)
                {
                    events.add(event);
                }
            }
        } catch (Exception e) {
            TestLogger.get().error("GrouponTest", String.format("gatherEvents doInBackground failed: %s", e.toString()));
        }
    
        return events;
    }
    }
    

    您需要在您的应用程序中设置以下权限:

    <uses-permission android:name="android.permission.READ_LOGS">
    

    我还创建了一个 LogEvent 对象来解析来自 logcat 的事件:

    public class LogEvent {
    String orignalString = null;
    boolean parsed = false;
    
    long timeMs = 0;
    String timeString = null;
    String verbosity = null;
    String tag = null;
    int pid = 0;
    String msg = null;
    
    // Lazy factory design pattern
    // http://en.wikipedia.org/wiki/Lazy_initialization
    public LogEvent(String s) {
        orignalString = s;
    }
    
    public long getTimeMs() {
        checkInit();
        return timeMs;
    }
    
    public long peekTimeMS()
    {
        // Time is always formattted as such: MM-DD HH:MM:SS.XXX
        return parseTime(orignalString.substring(0,5), orignalString.substring(6,18));
    }
    
    public String getTimeString() {
        checkInit();
        return timeString;
    }
    
    public String getVerbosity() {
        checkInit();
        return verbosity;
    }
    
    public String getTag() {
        checkInit();
        return tag;
    }
    
     public int getPid() {
        checkInit();
        return pid;
    }
    
    public String getMsg() {
        checkInit();
        return msg;
    }
    
    /**
     * Checks to see if the event message contains a substring
     * @param check
     * @return
     */
    public Boolean checkMsgSubstring(String check)
    {
        int index = orignalString.indexOf(check);
        boolean isSubstring = (index >= 0);
        return isSubstring;
    }
    
    public String toString()
    {
        checkInit();
        return String.format("%s %s/%s(%d): %s", timeString, verbosity, tag, pid, msg);
    }
    
    private void checkInit()
    {
        if(!parsed)
        {
            parseEvent();
            parsed = true;
        }
    }
    
    private void parseEvent()
    {
        try{
        String [] splits = orignalString.split("[ ]+");
        // Sometimes the PID is of format ( XX) instead of (XX)
        if(splits[2].indexOf(")") < 0)
        {
            splits[2] += splits[3];
            ArrayList<String> formatted = new ArrayList<String>(Arrays.asList(splits));
            formatted.remove(3);
            splits = formatted.toArray(new String[formatted.size()]);
        }
    
        // Parse time
        timeMs = parseTime(splits[0], splits[1]);
        timeString = String.format("%s %s", splits[0], splits[1]);
        // Parse tag
        verbosity = parseVerbosity(splits[2]);
        tag = parseTag(splits[2]);
        pid = parsePid(splits[2]);
        // Parse message (may be empty)
        if (splits.length > 3) {
            msg = orignalString.substring(orignalString.indexOf(splits[3]));
        } else {
            msg = "";
        }
        }
        catch (Exception e)
        {
            // TODO: there are some strangely formated events in the system. need to deal with these?
        }
    }
    
    /**
     * Time comes in following format: 08-11 20:03:17.182:
     * Parse into milliseconds
     * @param day string of format 08-11
     * @param hours string of format 20:03:17.182:
     * @return
     */
    private long parseTime(String day, String hours)
    {
        Time timeToSet = new Time();
        Time currentTime = new Time();
        currentTime.setToNow();
    
        // Parse fields
        String[] daySplits = day.split("-");
        if(daySplits.length < 2)
            return 0;
    
        String[] hourSplits = hours.split(":");
        if(hourSplits.length < 2)
            return 0;
    
        String[] secondSplits = hourSplits[2].split("\\.");
        if(secondSplits.length < 2)
            return 0;
    
        int _year = currentTime.year;
        int _month = Integer.parseInt(daySplits[0])-1;
        int _day = Integer.parseInt(daySplits[1]);
        int _hour = Integer.parseInt(hourSplits[0]);
        int _min = Integer.parseInt(hourSplits[1]);
        int _sec = Integer.parseInt(secondSplits[0]);
        int _mili = Integer.parseInt(secondSplits[1]);
    
        //set(int second, int minute, int hour, int monthDay, int month, int year)
        timeToSet.set(_sec, _min, _hour, _day, _month, _year);
    
        // return calculated value
        long parsedTimeInMili = timeToSet.toMillis(true) + (long)_mili;
        return parsedTimeInMili;
    }
    
    private String parseVerbosity(String s)
    {
        return s.split("/")[0];
    }
    
    private String parseTag(String s)
    {
        int verbosityLength = parseVerbosity(s).length() +1;
        String tagPart = s.substring(verbosityLength);
        return tagPart.split("\\(")[0];
    }
    
    private int parsePid(String s)
    {
        try {
            String pidPart = s.split("\\(")[1];
            return Integer.parseInt(pidPart.split("\\)")[0]);
        } catch (Exception e) {
            e.toString();
        }
        return -1;
    }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-22
      相关资源
      最近更新 更多