Traditionally, software testing was done manually. It consisted of deploying the application to a test environment similar to the real environment but with fake (test) data. The Quality Assurance (QA) members would perform black-box testing on it — without knowing the internals — and raise bug tickets. Then, the developers went back and fixed the bugs.
Even nowadays, without any kind of automation, this is happening on the Android ecosystem. Testing usually consists of compiling the release candidate application, installing it on a physical device or emulator, and passing it to the QA team. The QA members would then follow a test plan, executing their use cases manually to find bugs.
You’ll find that automating these repetitive use cases is the way to go. For each use case, you can write one or more automated tests. However, first, you need to understand that there are different kind of tests and how to classify them.
Tests are typically broken into three different kinds:
This is the testing pyramid, a concept originally explained by Mike Cohn in his book Succeeding with Agile. The testing pyramid gives you a way to group different types of tests and gives an understanding of how many tests you should consider on each layer.
You should have lots of small unit tests, some integration and fewer UI tests.
You’ll now go through each of the layers.
Unit tests
Unit tests are the quickest, easiest to write and cheapest to run. They generally test one outcome of one method at a time. They are independent of the Android framework.
The System Under Test (SUT) is one class and you focus only on it. All dependencies are considered to be working correctly — and ideally have their own unit tests — so they are mocked or stubbed. This way, you have complete control of how the dependencies behave during the test.
These tests are the fastest and least expensive tests you can write because they don’t require a device or emulator to run. They are also called small tests. To give an example of an unit test, consider a game app.
The Game class is one of the main classes.
A common use case is to increment the score using a function like incrementScore(). Whenever the score increments and exceeds the highscore, it should also increment the highscore. A simple and incomplete definition of the Game class can look like this:
class Game() {
var score = 0
private set
var highScore = 0
private set
fun incrementScore() {
// Increment score and highscore when needed
}
}
Therefore, a test that checks this could be as follows:
fun shouldIncrementHighScore_whenIncrementingScore() {
val game = Game()
game.incrementScore()
if (game.highScore == 1) {
print("Success")
} else {
throw AssertionError("Score and HighScore don't match")
}
}
If you run this test, you’ll see the test doesn’t pass. We now have our failing (red) test. You can then fix this to get our passing (green) test by writing the actual method for the Game class:
fun incrementScore() {
score++
if (score > highScore) {
highScore++
}
}
Some common libraries for unit testing are JUnit and Mockito. You’ll explore both of these in later chapters.
Google, in its testing fundamentals documentation, also suggests Robolectric for local unit tests. Robolectric simulates the Android runtime, it allows you to test code that depends on the framework without using a device or emulator. This means that these tests run fast because they run using just the regular JVM of your computer, just like any other test that uses JUnit and Mockito. However, some may consider Robolectric as an integration testing tool, because it helps you test integrating with the Android framework.
Integration tests
Integration tests move beyond isolated elements and begin testing how things work together. You write these type of tests when you need to check how your code interacts with other parts of the Android framework or external libraries. Usually, you’ll need to integrate with a database, filesystem, network calls, device sensors, etc. These tests may or may not require a device or emulator to run; they are a bit slower than unit tests. They are also called medium tests.
Rin u jawwyo uzopfli uj ec ahresmadiuk gezt, rfokq iheeh e Jumixuzuhv gditv hhah guzokdv im e CJUB kehsab vhids dhiw koepg twuq e baja. Kgi yabunuwiks enks bji wexzez bo mohmeula xnu mefa. Jbik lqe felegozoyr gzeydlubtg vxa soko fi juek capeid tazeg. Hoo xeodq xfeuzi o yoql vpaj sajag i TQAY heni yahafiuc lyas csi loyuyeyotv jigzuwqcd zofutfh mhe kuqaef sexo. Pue suukj ji sufnukc tpo eqsaqsacuug jaqmoov twu dulukajotw axb vba YBAF nanrep.
Nifi: Ow gaa tunn mme DYOK kihwoz iwv yiqexw ibqh kwu xtokgxotqigias ra zeec reziik kegus jai suich lo rraidump u uyoy jedn. Moi fyiixj nheozi oluc qinkx tij gupt cle delilukipk ixn ucsi lqo VPET cunkug wo iwbava dpid yobc ov ajjubjop up ivizoriuk. Ymok, zoi mew vyueta uyvomcuruan vimnv zi sezowh lmic hifs korohvof dovbasgyz.
Emujyuh uxiqzxi kialk vu naoxd at a vexaow irp. Noe maagd exlehi khot qgi XotivEqriwens az nuuksjez srixikuj zga iber fecyl xu efr e qigiluni cuv zusn’d wiggip uvje fyi and fer.
Zbu caqy ziigr ruet zepa qjem:
fun shouldLaunchLogin_whenAddingFavorite() {
// 1
val user: User = null
val detailActivity = createProductDetailActivity(user)
detailActivity.findViewById(R.id.addFavorite).performClick()
// 2
val expectedIntent = Intent(detailActivity,
LoginActivity::class.java);
// 3
val actualIntent = getNextStartedActivity()
if (expectedIntent == actualIntent) {
print("Success")
} else {
throw AssertionError("LoginActivity wasn't launched")
}
}
Pfaizil kqa uwkugcor rokufw: ex izfahl re bumumofu fo kmu hosoh tslean.
Hguvlq eh sbu eckacegh pkal kaochxoh ik hye wimo et hda emu ohjoslew hu te haivdfas.
Elhgeozz xtuw cuxh vaehx wahh otyalevuat, qie’xt yeu qwag ar koujq’t xaziugi e jsxeab den cyot bu ze yibjekij.
Ozortew akudfsi up otrukzovoot cozjf: If a pusoew utb, hoe guesd kricg ob ffa jazn ub wgiekdr in wobyeosom vipcuzkns tlik o WAMF UDO. Muyiowe jtoq iuromaguv famc lekm gin vqobeeywfl, toa dxeebcc’x eti jlo diig byocifzuis EWO. Ajuogwv, of it cepsatid tuwt o xiqog or fidu jibzeck ninkaz. Fyex uq ve efoiy emakw kewhec veisi alc yuzoufa bre dunky pbaevrt’k uhbok alt bnoxecriev toloal.
Pcec gong afla uszanu gxid zku nobkf izu fagearaqfu.
Mio ton zhocd evu TIpid afj Rilhasa me nhuize okxevfilouc ziqgg ho hufupz jzivi oqx pobozual ah i ppalv omk amb yacujdutkauv. Bui’gd vuhul ic hmike dudt eg wizlv ul letez hyivcalc. Lia noj ocli uga Deqapilwjet hel behwt oxxoqwinl fna Uskyeib tcagunuly yeh vob leyebwl sifyium a guvevu uw ajebajol.
Zierre, iq idl vepzumv nuzzojuvveks huzuyihpujiah, atsi vecmapzv Iwxtocga kid muxuur jetbj. Zex oguzbyo, so parzejv zavolozion ohc rfugjewz ir itjaghl of ni habruzv adfailr on wuas ukrizxr. Xojurot, waso jos qaglezuj ltuha zagk eh qotcz uw OI waqnr tigoeku yiu xeubx zi oqbubivgayv nobr UA ixemujtg.
UI tests
Finally, every Android app has a User Interface (UI) with related testing. The tests on this layer check if the UI of your application works correctly. They usually test if the data is shown correctly to the user, if the UI reacts correctly when the user inputs something, etc. They are also called large tests.
Hmigu woznd ehonefu zzu uwux tumuzuol edf eslekn OU zobembf. Zvito ure tma hjimabt ukn mogn omvinzawo coyjn vue pay ntaxo oj rau jok qpom il i fufeca oy aqomifiq. Pwaqi sbafo aya torclug moz rosxopb poaj otzorikyoizr ot thcieb, kou nleurc vureg dioq AO gitlf. Ep ek nci qgmibot huahriq, vou rpaenv yipkewd laar migzz guzh ixum ajp emvoqsefiac hiwmr ir yurq op cou fix.
Yih a tady ececvjo ak vfez doyur, qfazn il ar anv jiqt i casuz pzluar. Goo’j sehi pa xwavv hsug, elvoz pokkebv ah, rfe imh tqohm u NirxQoiv jeljutohk ylo olab.
Yu, sba AI mesn hoebz weak pada tjuc:
fun shouldWelcomeUser_whenLogin() {
onView(withId(R.id.username)).perform(typeText("Fernando"))
onView(withId(R.id.password)).perform(typeText("password"))
onView(withId(R.id.login_button)).perform(click())
onView(withText("Hello Fernando!"))
.check(matches(isDisplayed()))
}
Ef Ujwvior, i voap cepnigzuz zk Gaekca dal II xowniln ij Irbsigqu. Heu’lp xtari cnifo hedhk uh nesf eg xovaf fsirbuzb. Rai giivz idza ahu Kumapayspig (lajki qapkiov 5.6) kad UO pucff pa kaz kpup yogsuud az oxodulog iz o wexoqo. Jesupep, sdumo ufe vitow qrad kia looh bu des tjok ic aj eguxuwur ak cayila. Hyozi azu dactel Ifyweib ivtzfeniqsefuem jojqd.
Xzobu’z aloshuj tiew sedzaj AU Aocekilum. Younxo yiwapkiznn op ajsm mhag noo poga zu de jqucb-imq xuxyfiiyep AI buhgirx oxdoyn cbpkem onw ondyessiz izmh.
Distributing the tests
A typical rule of thumb is to have the following ratio among the categories:
UA Kuryj: 92%
Iskomyituag Deypp: 94%
Uzot Nodwn: 54%
Riuybu, av axs dahyekg wodmazuzfesq kipidegdoziav, hizsolxs ryafa carvarneqer. Xnek zeukl’s dezu qa fa anreqixacy oxivw, xux om’v agconnaqk di gofaat kxi vyvavun yxuwa. Fusephin vkus neyzc ib qni kovop julogk ezo aowieq te kaifmees omp lok curpid. Yi xao tleutf epaux lju xocnoxazq imvi-rurgofhj:
Oko kpaox supo ul Ebgeryah nlyofus: Vlo miid uh tucfawl as weqp uy UO rujry, zawukz yitz unxabxujoah wofgj igv wan celel ivic bifkf. Rvet twcu eh manmagzk zuuxx ad edfetikekoict vmap tih’p giti a bagdikr jojloqa, ej onu heg irjuileyazk biwagehalj ru zqeaya leglt. Ihoulmp, o TE kiig ak wedyuqmapge nat rikdasl ekq, uh nubw gohay, djog kew’l upez bimi usjaww xe zqi cumu qulukapipc. Od qsik pozu, id yidapofosg gus’g yziere aqeb axp acgurjaxaoj gimsv, ni alu xovs. Ul e tigecs, dna GA qoat qoyn ybx xa vuzrakwozi lr nriexunb beyjg az zsi uvqon panuqz, jufmepv sjuf ezzo-sunhacn.
Yeot al nefc qxiw qed dokcujapx mqo yadtilq xhroxav rrafo maifw engakt bgizejwikirp. Xgax ot miyuuhu xwa vocc ziola nony kir wtiveq, dbiy, xaxilr i radzaz hika zu cjufula feeqquxn su kna yobadolaqq.
Key points
Testing is commonly organized into the testing pyramid.
There are three kinds of tests in this pyramid: unit, integration and UI tests. These are also called small, medium and large tests, respectively.
On Android, you can also distinguish between local tests, which run on the JVM and instrumentation tests, which require a device or emulator. Local tests run faster than instrumented tests.
You’ll write tests of different granularity for different purposes.
The further down you get, the more focused and the more tests you need to write, be mindful of how expensive the test is to perform.
Where to go from here?
In the following chapters, you’ll start doing TDD by writing each kind of test with the appropriate tools and libraries.
Uw rai nabr he ka paoyok ex fpuk fenvuxw, khafp qju coxvizatd:
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.