2011-08-10 8 views
1

테스팅에 로보 티움을 사용하고 있으며, 타이밍 문제가 많아서 활동 (또는 뷰)로드가 완료된 시점을 알기가 어려워졌습니다. 결과적으로 제가 작성한 테스트는 그다지 강력하지 않습니다.안드로이드를위한 이벤트 기반 테스팅

테스트 프레임 워크에 푸시 될 수있는 이벤트로 테스트중인 애플리케이션을 계측 할 방법을 찾고 있습니다. 테스트중인 어플리케이션이 예상 이벤트가 발생할 때 내 테스트에 "알릴"수 있다면 매우 유용 할 것입니다. 나는 과거에 큰 효과를 내기 위해 windows \ windows phone에 Event Tracing for Windows을 사용했습니다.

내가보고있는이 작업을 수행하는 가난한 사람의 방법은 내 테스트 응용 프로그램에서 실시간으로 logcat을 읽고 예상 이벤트가 발생할 때 테스트에 알리는 것입니다.

다른 아이디어가 있습니까?

답변

1

이 문제를 해결하려면 OS logcat에 의존해야합니다. 추적 코드로 테스트중인 코드 부분을 테스트 코드에서 발생하기를 기다립니다. 아마도 그 일을 가장 잘 수행하는 방법이 아니지만 그것은 내 필요에 어울립니다. 나는 처음에 logcat에서 읽는 asynctask를 만들려고했지만 타이밍 문제가 발생했다.

:

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; 
} 
} 

당신은 응용 프로그램에서 다음과 같은 권한을 설정해야합니다 : (내가 EmSingleton라는 싱글에 싸여 그건)

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 코드 : 나는 마침내 이런 식으로 뭔가를 구현

<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; 
} 
} 
관련 문제