The real face of functional testing
This is a modal window.
Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.
Formale Metadaten
Titel |
| |
Serientitel | ||
Anzahl der Teile | 46 | |
Autor | ||
Lizenz | CC-Namensnennung 3.0 Unported: Sie dürfen das Werk bzw. den Inhalt zu jedem legalen Zweck nutzen, verändern und in unveränderter oder veränderter Form vervielfältigen, verbreiten und öffentlich zugänglich machen, sofern Sie den Namen des Autors/Rechteinhabers in der von ihm festgelegten Weise nennen. | |
Identifikatoren | 10.5446/47198 (DOI) | |
Herausgeber | ||
Erscheinungsjahr | ||
Sprache |
Inhaltliche Metadaten
Fachgebiet | ||
Genre | ||
Abstract |
| |
Schlagwörter |
00:00
SignifikanztestVollständiger VerbandSignifikanztestProdukt <Mathematik>Reelle ZahlBitProjektive EbeneKartesische KoordinatenStatistischer TestVorlesung/KonferenzBesprechung/Interview
01:11
Vollständiger VerbandRechenschieberRechenwerkWechselseitige InformationTouchscreenStatistischer TestKartesische KoordinatenBetafunktionBitProgrammbibliothekComputeranimationProgramm/Quellcode
01:38
E-MailSichtenkonzeptPasswortMessage-PassingFehlermeldungLoginAbstraktionsebeneGoogolProgrammbibliothekCodeSichtenkonzeptGüte der AnpassungPasswortE-MailFehlermeldungRechter WinkelLoginTypentheorieDatenfeldGruppenoperationKonfiguration <Informatik>Prädikat <Logik>Interaktives FernsehenTouchscreenMultiplikationsoperator
03:45
OvalAbstraktionsebeneFehlermeldungLoginPasswortE-MailSpannungsmessung <Mechanik>TypentheorieAbstraktionsebeneCodeStatistischer TestE-MailApp <Programm>PasswortRechenbuchSchreiben <Datenverarbeitung>FehlermeldungSichtenkonzeptMereologieComputeranimation
05:26
InternetworkingClientInternetworkingBitDienst <Informatik>MultiplikationsoperatorApp <Programm>Vorlesung/Konferenz
06:07
Abstimmung <Frequenz>Dienst <Informatik>CodeCoxeter-GruppeCASE <Informatik>Rechter WinkelUniversal product codeFehlermeldungInterface <Schaltung>InjektivitätDienst <Informatik>Klasse <Mathematik>Statistischer TestAppletUmkehrfunktionMailing-ListeObjekt <Kategorie>VorhersagbarkeitProdukt <Mathematik>Algebraisch abgeschlossener KörperBimodul
07:42
Interface <Schaltung>StellenringDienst <Informatik>MultiplikationsoperatorCASE <Informatik>Statistischer TestDienst <Informatik>ClientURLCodePunktAlgebraisch abgeschlossener KörperGoogolApp <Programm>AppletVorlesung/Konferenz
09:13
FacebookLoginInterface <Schaltung>OvalFehlermeldungKontextbezogenes SystemMathematikGamecontrollerGoogolFacebookFehlermeldungService providerDienst <Informatik>InternetworkingEinfach zusammenhängender RaumLoginBimodulStatistischer TestKonditionszahlImplementierungClientCASE <Informatik>GeradeCodeComputeranimation
10:58
Statistischer TestTouchscreenMarketinginformationssystemRechenschieberPay-TVSichtenkonzeptVererbungshierarchieKartesische KoordinatenTypentheorieApp <Programm>Vorlesung/KonferenzComputeranimation
11:36
OvalPay-TVSichtenkonzeptVererbungshierarchieFunktionalSignifikanztestTypentheorieInformationProgramm/QuellcodeComputeranimation
12:08
Pay-TVOvalVererbungshierarchieSichtenkonzeptCodeEreignishorizontSchaltfunktionGruppenoperationBootenZeichenketteInformationFehlermeldungDatentypMessage-PassingCodeBitSystemaufrufSichtenkonzeptAppletInformationZeichenketteDatensichtgerätComputeranimation
12:56
FunktionalEreignishorizontGruppenoperationDatentypFehlermeldungMessage-PassingVorzeichen <Mathematik>InformationInformationApp <Programm>ComputeranimationProgramm/Quellcode
13:32
GruppenoperationZeichenketteOvalPay-TVEreignishorizontBootenVererbungshierarchieHumanoider RoboterStatistischer TestÜbersetzer <Informatik>Statistischer TestCASE <Informatik>Konstruktor <Informatik>Kartesische KoordinatenKlasse <Mathematik>ComputeranimationVorlesung/Konferenz
14:51
OvalGruppenoperationÜbersetzer <Informatik>Humanoider RoboterInformationSichtenkonzeptDemo <Programm>TypentheorieHidden-Markov-ModellVorlesung/KonferenzBesprechung/Interview
16:11
Spitze <Mathematik>Humanoider RoboterHydrostatikÜbersetzer <Informatik>SichtenkonzeptAusnahmebehandlungEin-AusgabeGruppenoperationStatistikSinguläres IntegralStatistischer TestAutomatische IndexierungGruppenoperationTypentheorieSichtenkonzeptStatistischer TestProdukt <Mathematik>Coxeter-GruppeComputeranimation
18:43
AusnahmebehandlungGruppenoperationHumanoider RoboterHydrostatikSichtenkonzeptEin-AusgabeFlip-FlopCOMWärmeübergangKonvexe HüllePASS <Programm>BitfehlerhäufigkeitKartesische KoordinatenStatistischer TestProgramm/QuellcodeComputeranimationVorlesung/Konferenz
19:13
Humanoider RoboterWärmeübergangEmulatorPASS <Programm>RechenwerkTurtle <Informatik>DivisionSystemaufrufHydrostatikSpezialrechnerStatistischer TestSichtenkonzeptDynamisches RAMAppletTermCOMAusnahmebehandlungGruppenoperationVersionsverwaltungRechter WinkelComputeranimationProgramm/Quellcode
19:48
RechenwerkOvalPhysikalisches SystemSichtenkonzeptHumanoider RoboterStatistischer TestCodeZweiVorlesung/Konferenz
20:28
SichtenkonzeptStatistischer TestAusnahmebehandlungErwartungswertHumanoider RoboterHydrostatikGruppenoperationPhysikalisches SystemKreisringOvalStatistischer TestComputeranimationProgramm/Quellcode
20:59
ProgrammbibliothekÜbersetzer <Informatik>Singuläres IntegralBimodulCodeNabel <Mathematik>Statistischer TestHydrostatikUmkehrung <Mathematik>InternetworkingStatistischer TestBimodulUniversal product codeVersionsverwaltungKlasse <Mathematik>BitCodeEinfach zusammenhängender RaumProdukt <Mathematik>Computeranimation
22:52
p-BlockStatistischer TestNabel <Mathematik>MarketinginformationssystemInklusion <Mathematik>OvalCodeEin-AusgabeService providerComputersicherheitAppletInformationProgrammbibliothekHilfesystemComputeranimation
23:54
StellenringInklusion <Mathematik>Einfach zusammenhängender RaumStatistischer TestSpielkonsolePhysikalisches SystemDisk-ArrayBimodulProgrammbibliothekEin-AusgabeModul <Datentyp>SichtenkonzeptOvalHidden-Markov-ModellURLComputeranimationVorlesung/Konferenz
25:23
GammafunktionHumanoider RoboterFunktionalStatistischer TestStellenringNabel <Mathematik>ProgrammbibliothekFehlermeldungMomentenproblemComputeranimationVorlesung/Konferenz
26:17
Statistischer TestNabel <Mathematik>AusnahmebehandlungVererbungshierarchiePhysikalisches SystemSichtenkonzeptCodeFunktion <Mathematik>ZählenOvalPi <Zahl>StellenringGammafunktionBootenVersionsverwaltungVerknüpfungsgliedProdukt <Mathematik>Ordnung <Mathematik>BimodulComputeranimation
26:49
Statistischer TestVererbungshierarchieOvalSichtenkonzeptNabel <Mathematik>CodeProdukt <Mathematik>Einfach zusammenhängender RaumInternetworkingFehlermeldungVersionsverwaltungUniversal product codeDatensichtgerätFunktionalCASE <Informatik>BimodulKomponententestStatistischer TestEinfache GenauigkeitComputeranimationVorlesung/Konferenz
27:53
InformationOvalPhysikalisches SystemSichtenkonzeptNabel <Mathematik>AusnahmebehandlungStatistischer TestDisk-ArrayMathematikProgrammbibliothekBimodulFehlermeldungStatistischer TestLaufzeitfehlerComputeranimation
28:29
MagnettrommelspeicherStatistischer TestStellenringNabel <Mathematik>Physikalisches SystemSichtenkonzeptCodeHumanoider RoboterZeichenketteInverser LimesStatistischer TestExpertensystemFehlermeldungComputeranimation
29:30
Inklusion <Mathematik>ErwartungswertHumanoider RoboterStatistischer TestStellenringKette <Mathematik>MIDI <Musikelektronik>AusnahmebehandlungNabel <Mathematik>VererbungshierarchieKartesische KoordinatenTermCoxeter-GruppeStatistischer TestComputeranimationVorlesung/Konferenz
30:14
SichtenkonzeptKlasse <Mathematik>GruppenoperationOvalBildschirmsymbolLoopAusnahmebehandlungBitStatistischer TestMultiplikationsoperatorImplementierungZahlenbereichSchnelltasteCodeFahne <Mathematik>Computeranimation
31:31
Mailing-ListeBildgebendes VerfahrenSichtenkonzeptProgrammbibliothekCASE <Informatik>Statistischer Test
32:37
Statistischer TestAbstraktionsebeneProgrammbibliothekMultiplikationsoperatorBitAppletSkalarproduktKlasse <Mathematik>Vorlesung/Konferenz
33:30
BitfehlerhäufigkeitCASE <Informatik>ProgrammbibliothekCodeKlasse <Mathematik>InjektivitätVorlesung/Konferenz
34:08
InjektivitätSchreib-Lese-KopfMultiplikationsoperatorKartesische KoordinatenTwitter <Softwareplattform>Produkt <Mathematik>SoftwareentwicklerVorlesung/Konferenz
35:06
Vorlesung/Konferenz
Transkript: Englisch(automatisch erzeugt)
00:05
Hello, thank you for your introduction, let me run something, okay, so we can start. My name is Maciej Gurski, I'm here to talk about you, to get you a bit more excited
00:22
about functional testing and to show you it's not that hard to do that, even if you may think it's impossible for doing that for real applications, so that's my Twitter handle if you need it for anything. But before we start, I want you
00:46
to meet my product owner, Mateusz, a guy I'm working with for a few months, and because I'm working with him, I can be here actually, he allows me to write a lot of tests,
01:04
he's really into quality of our product, so let me show you what's there, yeah, you should probably see, that's from our application, that should be
01:20
released by now, but it's still in beta on Google Play, unfortunately, but yeah, it looks good, there are a lot of tests there, and yeah, it's all because of him, so remember him for a bit. So, Espresso, I'm here to talk about this new cool library
01:47
from Google, and yeah, it's still new, but what it allows us is to, instead of what we were doing manually, clicking in the UI to check everything is working, we can automate that, there were some other libraries before that, but this is
02:05
really, really easy to use, for example, if you have a simple login screen, we can make it click a few things, write some text, and in the end check if the error is shown there in red, some of you may see it, some maybe not, so how does it look
02:27
in the code? In the code, it's very simple, almost every time you do that, you start with onView, which is you create a view interaction with some predicate for this
02:44
view, for example, onView with some ID, or onView with some text, or any other thing will do, and then you have two options, the first thing is you can perform an action, for example, type text in an email or password field, or click
03:06
a button, and then after all the actions are done, what would a user normally do, you verify or check what happened, so in this example, we check
03:20
that our login error message view contains some text, simple, right? Looks good, but I don't really like to look at code like this, maybe it's simple in this example, but it gets complicated when you do multiple things and go to
03:44
another screen, so I like to abstract things, and let's think about, let's think for a minute, for a second, what's the first part, what does the user wants to do? Yes, they exactly, they want to log in, log in with some
04:03
email and password, that happens to be too short, so it's clear from this text that they want to log in, you don't have to analyse the Espresso test code, and the second part, yes, we just check the error message, so this
04:24
is the code I like, and what's inside? You would never guess, well, there is not the code that was there before, there is another layer of abstraction that makes you, makes it easier for you to read the code, so for example,
04:46
there is typed text in the ID, and the text you want to type. Another thing inside, there is actually the code that was there before, so we need to write it somewhere, but it's really good to abstract it,
05:05
so that's the code you would write, so by now, you would probably know how to write tests for calculator app, like 2 plus 2, type equals, and you check that on a view there is 4 shown, yes, but our apps do a little
05:28
bit more, usually, who is writing an app that doesn't use internet rest client? Nobody? That's weird, I do that all the time, no, so if you're
05:46
using internet, you're probably using retrofit for rest client, maybe where it's Java, if you are cool, so it doesn't matter much, but you have this service that you subscribe to, and after the work is done
06:05
in the background, you just show something or show the error, right? And to make tests easy, you cannot instantiate this service in your UI code, in your activity or fragment or presenter, you have to
06:23
inject it, you have to use dependency inversion, so in my case, I'm using Dagger to inject services in UI code in activities, and well, for production code, it's the code that you would normally have
06:44
there, like rest adapter and creating the object from the interface that was defined somewhere, but in tests, you can create a module that overwrites what happens in production, and simply return a
07:05
value that you can assert on, that you know that will be there for you, so there is predictability of that, and it just works, so in
07:22
case you are using Eric's Java, you return observable list of some stuff, for example doctors in our case, and you may not recognize this, because this is groovy code, it doesn't matter much, it's like anonymous class in Java, so a closure in this case,
07:51
what about other things, our apps use GPS from time to time, well is it any different, where there is this location client from
08:02
Google, and in my case, I try to abstract the code I don't like, like the APIs from Google are not that fun to use, so we create a simple location service, and we expect it to return location
08:22
at some point in time, so it's also asynchronous, it basically works like our rest client, so in the tests, we simply overwrite
08:41
what location service returns for us, in my case it is some location in Poland, and we can assert on that in tests, in this case it doesn't even matter what you return, you could just return observable of no, because the value is used for another
09:02
service to call the API, and it basically doesn't look at the latitude and longitude there, so it doesn't matter much. What about other things, like Google pass login or Facebook login,
09:20
you cannot have control over that, right, well there is a button you put into layout, and you cannot possibly use dagger to inject into layout, or is there anything change in dagger too? No, I don't think so, so what can we do with this
09:41
Facebook login, how can we test it? Well, we can inject a provider for this button, and not add it to the layout, but do it in code, so we have this provider, and the implementation
10:03
will be simple, it will create a new login button, and add it to the container, add some callbacks, and it will work. In tests, we have another implementation that adds a normal button, that on click, just calls our callback instantly, so
10:25
we won't have any lag, we won't have any connection to internet, to Facebook services, nothing like that, so basically it's the same case like the first one, with rest client,
10:42
and in case we want to check in our tests error conditions, like there is no internet, and we click Facebook button, what happens? Well, we switch one line in another module in tests, it looks awesome, so I could talk to you about this
11:02
for like maybe two more minutes, about all the things you can do, but I think we could switch to code, so I have this simple application, I should show it to you, yes,
11:24
this is an application that you can type your, sorry, GitHub user name, I will make it larger, not rotate, but larger, okay, so if I type my user name, and GitHub
11:54
user name, and click enter, I see some information about me, like who am I, where I work, where I live, it's using
12:04
GitHub API, so nothing fancy, let's look at the code for a bit, it's using dagger, it's using retrofit, or it's Java, so there is this on create view, where the layout is created, simple, we need the views, also simple, and
12:24
on enter we do something, like call folder user, which is basically using Java and retrofit, and after that, if you look here, we subscribe with display user method, which shows some information about the user, so the full info
12:45
about user, or if user didn't provide any information about themselves, there is a predefined string to show empty user, so if I do something else, like 8 0's, there is a
13:03
guy from Japan, yeah, some people like to use different strange handles, and I will make it smaller, someone called themselves, like, in C, if you can read C code, some
13:22
includes, defines, doesn't matter, and there is a user who didn't provide any information, so the app works. So we want to write some tests for it. I usually do it like that, that create a happy path of the application,
13:43
and then only then start writing functional tests, it would make real sense, not much sense to create a test first, and then go to create layout and stuff like that, so let's go
14:01
to some tests, we will create new, let's be groovy class, main activity test, of course our tests need to inherit from this weird class, activity instrumentation test case 2,
14:26
and they need to have some constructor without this, okay, so we have a class, so the first test we would write is
14:42
for the happy path, probably, so if we press enter after typing some text, we expect to see some text about the user, probably, so let me add a method, shows info about user,
15:09
and what we do first, we do on view, we want to type some text, sorry for that, usually happens during demo, why
16:05
doesn't, let me think, yeah, works now, so let me switch
16:45
to presentation mode, I started to import that, so we want to do on view with some text, sorry, with ID, we have
17:02
text ID, yes, should work, less text is better, and it's groovy so we can skip some parenthesis, doesn't matter, and we want to perform an action, type text, this will
17:30
be me, okay, and then on other, oh, no, and we want to
17:40
press action button, yes, or actually no, because this is this ID, and then we want to confirm that the other view, which is text view, check, and it contains the same thing
18:16
we have seen in the production, so it will be something like
18:20
this, and there is one thing missing, and if you run this
18:43
test now, what do you expect to happen? Let me switch the tests and run it, let's see the application, so any clue what will happen?
19:11
Exactly, if it runs, and it failed, oh, there is another
19:30
reason why it failed, because, let me make it closer, you need to call get activity, because it starts activity, and it makes sense, right, like gather starting activity, well,
19:46
they changed that in recent versions of Espresso, but this is what we have in our code base, and yes, it still failed because it didn't contain the text, so we can fix that, we
20:04
can make it sleep for 10 seconds, and this will work, right, it's running, and yeah, no, it failed, yes, exactly,
20:31
thank you, now I hope it will be okay, fingers crossed, so
20:49
we are done, or we need to wait for the test to finish, yes, cool, so, but this is not the way we should write
21:01
tests, they should be faster, a bit at least, so I have this injector in our production code, where we can set this modules, unfortunately, one thing for tests need to be in production code, and we can create a module like success
21:27
module, or test module, and let's create this class, so
21:46
it's a module, so we annotate that with module, and it overwrites some stuff, and for groovy, you need to do this, doesn't matter much, and what we wanted to do is
22:02
for our GitHub API to be provided, but not the slow using internet connection version, but we want to return something that returns observable with the text,
22:38
usually don't write this long text for test code, let's
22:44
statically import it, and now everything will be a bit faster, or no, why it didn't work, oh, annotation, of
23:29
course, you know Dagger, who doesn't know Dagger, there were talks about it, so if you missed them, I can't
23:43
help you, sorry, it still fails, or I didn't run it,
24:08
what's wrong now, oh, because, yeah, the API, I
24:25
completely forgot it, let's see at the API, which is here, it actually returns a user, so groovy, it didn't compile for some reason, even with compile static, so we
24:42
need to return a user here, and there is this name, component, location, name, component, location, yes,
25:33
almost, we are really, really close there, the text is
25:47
still blank, let me call the setter directly, a moment of
26:14
silence, now, of course, again, the wrong order,
26:23
because when the get activity is called, it starts activity and injects production version, and then just changing the module won't inject it again, so yes, it worked now, let's see it again, yay, thank you, yes,
26:54
so that's not all, we want to make an error version of it, so for example, in our production code, we have when
27:05
we, when there is internet connection error, we display error, or for any other reason, like there is no user, and it's all defined in some ugly switch case, switch case, for all the cases,
27:23
for things like that, you should probably use unit tests to cover all the cases, but a single test for functional tests should also be considered, so let me quickly add an error test module, and
27:48
another test, let's just copy it, shows error, and error test module,
28:07
and our module will return runtime error, so
28:21
in our tests, let's first run it, and see it fails, yes, there is this
28:41
test which expected some error, so we can fix that, and here I will simply copy it from resources,
29:05
which error was that, probably this, our experts know nothing about this error, and run it again, okay, so everything's correct now, that was
29:47
faster, so let's go back to application, to our presentation, and yes, that's very simple, but in Espresso, not everything is
30:02
like plain and simple, and if you start testing, there are some things you need to remember or learn the hard way, like we did, so for example, if you write more than two tests, and they will start another activity,
30:21
Espresso will not close all the activities, and the next test will fail, so you need to add, press back several times from your teardown after the test is finished, so what's the implementation, my favorite number is six, so we we do that six times, and we catch some exceptions,
30:42
and it works, yes, another thing, if your device is showing keyboard, well, Espresso is not fast enough to close the keyboard, and then continue, it continues before the keyboard is fully closed, so you will have some tests randomly failing from time to time,
31:04
or often, so we use Travis CI to run our tests, and on Travis, when the build is made on Travis, we have this flag, and we check it in our test code
31:20
to sleep for a bit after closing keyboard, and it works, but it's slower, that's sad, but it works, and Espresso, well, it's new, maybe not that new, but there's still a lot of things missing from it,
31:43
so you will end up adding your matchers, and a lot of them, for simple stuff like confirming if your view is showing an image with ID, like predefined resource, or other stuff,
32:01
especially if you're working with recycler views, well, there is a contrip library for Espresso, it contains some stuff, but in our case, it was not sufficient to write complex tests, so you will end up with code like that,
32:20
so, but basically, if you abstract it, you probably will have you find yourself easier to read, so with our Dr. House, we check if his calendar is displayed, so abstract, always abstract, and to finish this,
32:42
let's see what we've learned today, that, well, Espresso is expressive a bit, in Groovy, it's more fun, I found it the first time I started using Espresso in Groovy, without all the dots, it's very readable compared to Java,
33:04
but most of you probably using Java, it's still really, really nice compared to Robotium, and again, remember to abstract your code, so in the end, you could replace Espresso
33:21
with any other new library that will come later, just in a few classes, there will be dependencies to Espresso, I like to do that, I like to replace libraries when they don't work anymore, but Espresso is working really nice, except for these few cases,
33:41
and always remember dependency injection, dagger in our case, so it will help you, even in cases when you wouldn't think about, it could, always try to remove the code that's not your,
34:00
and wrap it in small classes that you don't have to test, they are simple, yes, and not all the things are easy, you will find yourself banging with your head in the wall from time to time,
34:21
and now, if you really like this talk, if you learned something, or if you confirmed your knowledge, what you already do, it's time to thank my product owner for it, so please tweet to that guy, you can, for example, take a picture of someone around you or something,
34:44
or ask a stupid question when we release the application, because we are waiting for that as developers, but there's some business there, so it's now time for you,
35:04
and I will take a picture of you, of course, so please smile.