A reader suggested that we write an article introducing the AppiumServiceBuilder functionality built into the Appium Java client.
All of our example code assumes that an Appium server is already running, and this is how many test suites start out too. It's so much more convenient if an Appium server is started automatically when the tests begin. The Java client has a convenient couple of classes for starting and stopping an Appium server. Other languages may have separate packages for doing this, or you can execute the Appium command as a separate process.
Check out: Batching Appium Commands Using Execute Driver Script to Speed Up Tests
Node.js has the advantage of being the language Appium is written in, so an Appium server can be started just by requiring it:
Back in Java land, we start by creating an AppiumServiceBuilder which we then use to create an AppiumDriverLocalService:
Now that we have an AppiumDriverLocalService named server, we can start and stop it easily. When starting, an Appium server will run, and you will be able to connect to it. The Appium server logs, by default, are printed in the output of the test.
Accelerate Appium test cycles with the HeadSpin. Learn more!
Don't forget to stop the server when you are done:
In order to run an Appium server, the Java code in the AppiumServiceBuilder needs to know the location of the Node.js executable on your computer, and also the location of the Appium package itself. It has ways to guess the location, but those did not work on my machine, since I installed Node.js using nvm. If you only have Appium Desktop installed, you will also have to install the Appium node package, so it can be run from the commandline.
Also check: Testing Windows Desktop Apps with Appium
If you share your test code with a team and/or run in different CI environments, you can set this information via environment variables rather than hardcoding file paths in your test code. Store the paths in environment variables named NODE_PATH and APPIUM_PATH, and the AppiumServiceBuilder will pick them up automatically.
Another issue I ran into is that the XCUITest driver requires the Carthage package manager to be in the system PATH. If you followed the installation instructions for XCUITest driver, Carthage is installed using Homebrew and it is automatically added to the PATH, so this isn't normally an issue. Unfortunately, the way that AppiumDriverLocalService runs Appium, it does not re-use your defauly PATH and instead reverts to the system default. For my case, I corrected this by specifying a new PATH environment variable in the AppiumServiceBuilder:
You can add other environment variables for Appium using this same method. You can also specify other options, such as custom desired capabilities that Appium should default to, and custom ways of exporting Appium logs.
Read: Capturing Browser Errors and Logs in Android Web/Hybrid Apps
For my tests, I decided to use serviceBuilder.usingAnyFreePort();, so that when my tests run, the Appium server will use any available port, rather than insisting on using port 4723. This way, if I have a forgotten Appium server running in another window, it won't interfere with my tests.
If Appium starts on a random port, our code to start a session needs to know what the port is so the client can connect to it. To solve this, I connect the client this way:
The AppiumDriverLocalService object has a getUrl() method which will return the URL and port of the Appium server it started.
There are more methods you can use to customize the Appium server programatically. Check out the documentation here and try experimenting: https://appium.github.io/java-client/io/appium/java_client/service/local/AppiumServiceBuilder.html
Here's the full example, putting all this together for a sample test. As usual the full example code is also available on github.