I have noticed that there are some questions asking how to retrieve device logs, and I think it would be worthwhile to share this little bit of information available from the Selenium API.
If you take a look at the WebDriver interface Javadoc, you'll see there's this neat little method called "manage()". This method returns an object whose class implements the WebDriver.Options interface. Inside this interface is a collection of tools that are incredibly helpful, which you should definitely take a look around on your own time. In particular, however, is a method called "logs()". Calling this method returns an object whose class implements the Logs interface. Within this interface is another method called "get".
This "get" method takes in 1 String parameter. The parameter is used to determine what type of logs the method should return. There are a set of predefined values available to give to this method, but Appium defines a log type of its own for Android tests called "logcat". As the parameter value suggests, the logs returned here are the Android logcat logs from the device under test at the moment! As a quick example:
AndroidDriver<AndroidElement> driver = blah blah blah
LogEntries entireLogBuffer = driver.manage().logs().get("logcat");
Iterator<LogEntry> logIter = entireLogBuffer.iterator();
LogEntry entry = logIter.next();
There are some additional things to note when retrieving logs. When Appium starts a session, it pulls in the entire device logcat buffer without clearing the buffer (maybe there should be a desired capabilities option to clear the buffer? Hint hint nudge nudge). This means it is possible to see the same log entries in separate test sessions.
Also, when you call the "get" method multiple times, each call only returns the log entries newer than the last call to "get". Essentially, you're only given each log entry once per test session.
How Appium stores the logs:
When Appium starts a test session, Appium also spawns a separate process running
adb logcat (with additional options to set the output format). Appium will read standard out from this process and store the results within an internal buffer. When Appium receives a call to retrieve the logs, Appium returns whatever is in its buffer. I'm pretty sure Appium also clears the buffer at this point, but I haven't dived through enough Appium code to confirm if this is the case.
What I use this for:
The application I'm working on logs the URLs it requests. The data returned from these requests determines how the application behaves in later steps. By scanning the logs and parsing out the URLs, I can make the same HTTP requests to verify if the application's behavior is consistent with the data in the response.
What else can I use logs for?
Although Appium advertises itself as a project where you can build your tests without modifying your application, I believe that a small amount of modification can lead to lots of benefits. In particular, the application can log some data that is necessary for tests to know. When the test runs, it can pick up that data from the logs. You can use the logs as a subtle method of sending data from the app back to the test without having to change the UI. This works out even better with Android's Gradle build system, since logs are usually enabled for debug builds, and disabled on release builds.
In many cases, there might not be any need for modifying the application source at all, as there are logs being made for other uses that happen to be useful for tests as well.