TDD of Python microservices
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Part Number | 151 | |
Number of Parts | 169 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/21185 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
EuroPython 2016151 / 169
1
5
6
7
10
11
12
13
18
20
24
26
29
30
31
32
33
36
39
41
44
48
51
52
53
59
60
62
68
69
71
79
82
83
84
85
90
91
98
99
101
102
106
110
113
114
115
118
122
123
124
125
132
133
135
136
137
140
143
144
145
147
148
149
151
153
154
155
156
158
162
163
166
167
169
00:00
DemonWeb serviceWaveDifferent (Kate Ryan album)CASE <Informatik>Web servicePerspective (visual)Software developerDecision theoryLecture/Conference
01:06
IntelElectronic mailing listComa BerenicesBlogComputing platformStatistical hypothesis testingWeb serviceConnectivity (graph theory)Block (periodic table)Multiplication signProjective planeExtension (kinesiology)Right angleComputing platformWindowOffice suiteLimit (category theory)Video gameComputer hardwareAnalytic setSystem callBlogCodeOpen setIndependence (probability theory)Android (robot)Computer animation
02:21
Web serviceIndependence (probability theory)WordDebuggerGoodness of fitSoftwareSource codeFront and back endsWeb serviceBlogComputer programmingLevel (video gaming)Pole (complex analysis)Block (periodic table)Computer animation
03:26
BlogEvent horizonData modelProcess (computing)Fault-tolerant systemKeyboard shortcutWeb serviceTask (computing)Data managementRevision controlControl flowIntegrated development environmentMobile appDivisorNatural numberConfiguration spaceMultiplication signDivisorIntegrated development environmentVariable (mathematics)Branch (computer science)BitWeb applicationProjective planeCode12 (number)Rule of inferenceDatabaseWeb serviceWordComputer programmingWeb 2.0Mobile appBoundary value problemComputer animation
04:56
Projective planeCode1 (number)Multiplication signSpring (hydrology)Java appletMoment (mathematics)Software bugAdventure gameTask (computing)MathematicsSoftwareProduct (business)Goodness of fitWeb serviceProcess (computing)Library (computing)Computer animation
06:39
Web serviceExecution unitStatistical hypothesis testingMobile appProcess (computing)Confidence intervalHoaxSystem programmingStatistical hypothesis testingProcess (computing)Web serviceStatistical hypothesis testingConfidence intervalGoodness of fitElasticity (physics)Proof theoryNP-hardReal numberExecution unitException handlingPhysical systemSet (mathematics)CodeCartesian coordinate systemLine (geometry)Product (business)Degree (graph theory)Bit2 (number)DatabaseWindowLocal ringJava appletSoftware developerBlock (periodic table)Mathematical analysisCross-platformSocial classSheaf (mathematics)Unit testingGroup actionMultiplication signWebsiteCASE <Informatik>Bit rateProjective planeMereologySystem callGene clusterComputer animation
11:48
RAIDCodeStatistical hypothesis testingExecution unitMountain passCode refactoringConfidence intervalRoboticsGradientIntegrated development environmentMathematicsLengthEndliche ModelltheorieBuildingStatistical hypothesis testingStatistical hypothesis testingWeb serviceConfidence intervalBranch (computer science)Connectivity (graph theory)Goodness of fitContext awarenessPhysicalismWater vaporCartesian coordinate systemFunctional (mathematics)InternetworkingSoftware developerProjective planeMultiplication signLevel (video gaming)Cellular automatonExecution unitCASE <Informatik>Unit testingLink (knot theory)Loop (music)Test-driven developmentGreatest elementComputer animation
15:04
ImplementationWeb serviceComa BerenicesControl flowStatistical hypothesis testingError messageDependent and independent variablesInstance (computer science)Process (computing)ImplementationProcess (computing)Cartesian coordinate systemServer (computing)Functional (mathematics)Strategy gameUniform resource locatorWeightWeb serviceStatistical hypothesis testingData managementInterface (computing)Variable (mathematics)CodeSlide ruleSheaf (mathematics)Perspective (visual)Open setModal logicData acquisitionSurfaceFormal languageData structureStandard deviationStatistical hypothesis testingDatabaseObject (grammar)CASE <Informatik>Logic synthesisMomentumRevision controlDeclarative programmingVarianceArchitectureResponse time (technology)Open sourceIntegrated development environmentDependent and independent variablesWhiteboardMultiplication signMedical imagingAuthorizationPattern languagePositional notationClient (computing)HypothesisConnected spaceBit rateNeuroinformatikStructural loadEntire functionLibrary (computing)Java appletRewritingString (computer science)Physical systemComputer animation
23:05
Statistical hypothesis testingWeb serviceStatistical hypothesis testingExecution unitMobile appComputing platform2 (number)Task (computing)DatabaseProcess (computing)Gene clusterStatistical hypothesis testingWeb serviceStatistical hypothesis testingBootingMultiplication signMultilaterationVirtual machineMedical imagingComputer animationLecture/Conference
24:04
Error messageBlogWeb serviceStatistical hypothesis testingWeb serviceFunction (mathematics)Address spaceMultiplication signProcess (computing)Level (video gaming)Statistical hypothesis testingControl flowIntegrated development environmentVirtual machineComputer animation
25:29
Statistical hypothesis testingStatistical hypothesis testingCartesian coordinate systemMathematical analysisVariable (mathematics)Linear regressionWater vaporRevision controlJava appletLibrary (computing)Design by contractBitLoop (music)Computer animationLecture/Conference
26:39
Source codeCodeStatistical hypothesis testingRight angleLibrary (computing)Group actionSystem callComputer configurationProcess (computing)SequenceParameter (computer programming)Statistical hypothesis testingWeb serviceComputer animation
27:40
Statistical hypothesis testingStatistical hypothesis testingExplosionBinary fileMathematical analysisLink (knot theory)Process (computing)PredictabilityState of matterMathematical analysisWeb serviceReal numberCodeStatistical hypothesis testingStatistical hypothesis testingMultiplication signParameter (computer programming)Normal (geometry)Server (computing)CuboidLecture/ConferenceComputer animation
28:54
Interface (computing)Design by contractStatistical hypothesis testingInformationRevision controlFlow separationCodeDependent and independent variablesData typeString (computer science)File formatObject (grammar)Single-precision floating-point formatBoolean algebraWeb serviceClient (computing)Formal verificationParameter (computer programming)Codierung <Programmierung>Execution unitComa BerenicesLarge eddy simulationAuthorizationVideo gameDataflowInterface (computing)Design by contractLine (geometry)Right angleReal numberAdditionWeb serviceINTEGRALDifferent (Kate Ryan album)Standard deviationSynchronizationClient (computing)Statistical hypothesis testingStatistical hypothesis testingWeb browserComputing platformFlow separationIntelligent NetworkObject (grammar)Message passingWeb 2.0Parameter (computer programming)Execution unitUnit testingFormal languageIntegerParsingExpected valueCodeLevel (video gaming)Type theoryField (computer science)Mobile appProcess (computing)Representational state transferSoftware frameworkMultiplication signCurvatureResultantSummierbarkeitWeightComputer filePlanningLibrary (computing)Dependent and independent variablesFamilyContext awarenessMoment (mathematics)Matching (graph theory)Social classEndliche ModelltheorieComputer configurationTrailNormal (geometry)Computer animation
33:58
Statistical hypothesis testingWeb serviceOptical disc driveContext awarenessRoundness (object)Design by contractProcess (computing)Physical systemExploratory data analysisMultiplication signSource codeFood energyTheoryComputer animationXMLProgram flowchart
35:01
BuildingStatistical hypothesis testingPhysical systemStatistical hypothesis testingWeb serviceComa BerenicesReading (process)Personal identification numberCartesian coordinate systemExecution unitLecture/ConferenceComputer animation
35:48
Statistical hypothesis testingQuicksortCartesian coordinate systemMereologyIntegrated development environmentInstallation artLecture/Conference
37:03
DemonRed HatComputer animation
Transcript: English(auto-generated)
00:00
Okay, so we're here for the last speaker of this session. Last speaker is Michal Bultrowitz with Test-Driven Development of Python Microservices. So can you hear me from, when I'm here, do you hear me in the end? Great, so I will be talking fast
00:21
because I have a lot of stuff to say, so if I start to mumble, just wave at me, okay? Just do this and I know that I need to go slower. So another microservice talk, but from slightly different perspective, yeah? I'm Michal Bultrowitz and I'm going to be telling you
00:40
my story with microservices and TDD and yet they will be REST microservices. They are fine in some cases. They are bad in others, but you know, like everything. It's not gonna be much about how to do TDD. It's gonna be more about tools you need
01:00
for TDD of microservices and services in general. So yeah, who am I? Well, as a professional, my whole life was at Intel. I did some stuff with distributed testing in C sharp on Windows and we had components on Android and Linux written in Java.
01:25
Then I went on to a project with C++ code for hardware backed secure channels, but finally, I've managed to get myself to a microservices project
01:41
and microservices based on Platform as a Service, actually, Cloud Foundry and it's called Trusted Analytics Project. It's open source, la, la, la, la, la. You can check it out, but you know, all good things come to an end and I've decided that it was time for me to move on, so now I am an independent Python researcher,
02:01
so yeah, I am unemployed for some time now. So if you have a few bags of gold lying around and you have offices in some nice place over the world, you know, like call me, whatever, and I'm trying to get a blog together, but you know, it's not there yet, but this is my GitHub, most of my stuff is there.
02:22
So microservices, what are they? If you somehow, you know, missed them through all those talks this year and last year and on all other conferences and blogs from all over the world, well, they are services, web services. They live on the network
02:40
and you know, mostly in the back ends and middle words. Sometimes the front end stuff can, you know, pretend to be microservices, but it mostly isn't, you know. Front end tends to be big. They are micro and this is hard to define, but generally they should do one thing well,
03:01
like, you know, all good Unix programs. They act independently of one another. They are only interested in what comes in, what they then put out and on their data sources and whole rest of the world doesn't interest them.
03:21
But for them to actually be able to do something real, they need to work together. And there are guidelines for creating microservice programs and actually there are good guidelines for any web applications. I think, I thought that this 12 factor app thing
03:42
was created in Heroku, but supposedly Martin Fowler came up with it like many, many years ago, whatever. Definitely check out those rules. I think the most important things are that services need to be stateless. So if you want some state, put it in a database. They should have one code base,
04:01
so no branches for deployment to other environments. No, you have one branch, one code for your service. If you want to configure it to some other environment, configure through environment variables. There you go, works fine. Word of advice, you know, word of caution. Don't go into microservices in the beginning.
04:22
When you start your project, just start with a good old web app, a monolith. Just try not to write it in a shitty way with spaghetti code. It will be fine probably. And just start cutting out bits and pieces when you get to know what your project is actually doing.
04:42
Because if you start with microservices, you'll spend way too much time just thinking about what we will be doing in the future and what boundaries should we define. It's not worth it. So yeah, my adventure with the amazing project.
05:00
Yeah, it was fine. I finally went into doing backend stuff, so I have a dream about it for some time. Sadly, I need to do a lot of Java, boot, Spring Boot, don't know if you know about it. I hate it. But I was actually able to create my own Python microservice, and I think that it was doing rather well
05:21
among other Java ones. And you know, the project was growing from like six people. We went to 70 in some time, so it was pretty interesting. And you know, I've got those all new kinds of interesting tasks to do. But yeah, more people, more tasks.
05:41
I didn't have enough time to look over my little pet service, and sometimes, you know, pretty embarrassing bugs would get through my review, even my own code. You know, it was just a small change. It shouldn't do anything bad,
06:00
but it wouldn't start in production, the code. So yeah, a few embarrassing moments. And even some of the dreaded interns needed to do comments on my code, and I didn't have the time to review them thoroughly because I had stuff to do. And then yeah, they would break the service,
06:22
and I would have less time to do my stuff because I needed to debug my service, and it was not well. So you know, what could I do about it? Tests, of course, of course, tests, like the solution to everything. You have problems with software, probably you don't have tests, but I had those.
06:41
And we had, you know, 85% coverage, which was at that time good among our services, but you know, it was a proof of concept, stuff like that. But yeah, they were getting pretty complicated, you know, hard to read, hard to maintain, a lot of mocks, ugly mocks for everything. And the funny stuff was,
07:01
with all the mocks and lines of code for tests, they didn't actually check if the service will just run. If you do the Python app, they didn't check that. But why aren't tests supposed to do that? Well, those were unit tests, and unit tests don't check if your whole blob works.
07:24
They only check if bits of blob, of the blob work on themselves. So you know, I needed something new, and why don't, you know, start the whole process like it's on the cluster, like in production,
07:41
and just, you know, call it like it would be normally called. Why not do that, you know? That, configure it in a way that the application doesn't know that it isn't in production. You know, no ugly local classes, except for real elastic search connections, for example.
08:00
And it would be even better if I could run those tests locally, before submitting a pull request, or actually, you know, for the other people, if they could run the test locally before they submit a pull request to me, you know, it would be fine. And you know, with that, I would have a pretty high degree of confidence
08:22
that the code that was committed would actually run when it goes to production. But yeah, it's kind of hard. You see, you have this thing that, no, you have this service, and has this database, let's say, but your service depends on another service, and this service depends on another service,
08:41
and stuff like that, and stuff like that. So how do you test it locally, you see? And it's kind of hard to set up, right? So yeah, about external services, you can deal with that in tests.
09:02
You have applications that mock out or stop services. They actually, you know, you have stuff like Wiremock, an old Java veteran, which is a process that you can start, and you can configure it through HTTP calls for it to start serving HTTP on other ports.
09:24
So basically, to start pretending other services. There's also a thing called Pretenders in Python. It can be easily used from normal-looking tests, but I didn't use it a lot. I don't think that it's really feature-full,
09:42
but you know, your mileage may vary. And there's also a thing called Mountebank, which is basically Wiremock, but better and with more features. And it isn't written in Java, it's actually Node.js, but you can just download a whole binary package for your system and not install any dependencies,
10:01
so good stuff. Second thing, databases, you know, my elastic search. I could just tell everyone to install it before they run tests, but you know, we had other services, so then they would need to install Redis for another service, and you know,
10:20
whatever for some other service. So you know, junk would pile up on our systems, and it was tiresome, you know. Why do you need to do a lot of stuff just to get to work on a project? So yeah, it wouldn't make the tests fun if tests can be fun. I don't know, they are fun for me.
10:40
So yeah, there is a thing called verified fakes, but not many people do that. It's something like that, imagine that you're creating a database, and you already, along with your code, you distribute a test double for people to test against your database,
11:01
and you test that your test double actually behaves like your database. This is a thing called a verified fake, and I don't actually know of any people who do them, but they will be pretty sweet in some cases, but yeah, nobody does them. It's just too much time.
11:21
But you have another buzz word, Docker. You can just, you know, you want Redis, just pull Redis, run Redis. That's it, and the only dependency that your tests have is Docker, and nothing else, so good stuff. But you know, it was supposed to be only on Linux. Now I heard that it's on Windows and OS X,
11:41
but you know, multi-platform, so now it doesn't work as well everywhere, so yeah, use Linux. Okay, now we have the basics for our TDD tool, so let's, you know, grab a broader context. So our magical tests of the whole application
12:03
are actually, you know, component tests. Component tests, according to Martin Fowler, I stole the slide from him. There's a link at the bottom. Yeah, there's a lot of names for those kind of tests in building microservices from O'Reilly, a great book.
12:21
They are called service tests, and I tend to use this name, but you know, component tests, service tests, or in Harry Percival's book, Test-driven Development with Python, I think, those, these are called functional tests.
12:40
So you know, all those things mean about the same thing. And this is TDD. This is all you need to know about TDD. I won't go deep into it, but you know, the general idea is that you write a functional test or a service test, then you see it failed, then you write a unit test, you know, write some code, write unit test, write some code, then you have, you know,
13:00
your functional test passing, you have one feature, then do it again, again, again, again, again, whatever. So this is the double loop TDD, I think it's called, or outside-in TDD, and sometimes it involves a thing called wishful coding, so yeah, TDD, do it.
13:21
But we don't have time to go into details. So I've noticed that TDD was exactly what I needed to save me in the project. I, it gave confidence in face of change, you know. I wouldn't need to push to the staging environment to see if everything is actually working, you know.
13:41
I could just run the test, the robot does everything for me, and you know, I could take someone's branch from pull request, and even if I didn't trust them to run the test, I could do it myself easily, quickly. So yeah, I would like, I craved for something like that.
14:05
One good thing about TDD, it's, you know, it tends to work on bad design. You don't need to get good design, no, no, but you know, when you need to test stuff, you tend to write them in a way that is less obnoxious to call, yeah, so.
14:23
This, but TDD has one critical flaw, it requires discipline, you know, it's, you need to practice TDD, you need to think about TDD, you need to live the TDD way, you know, like you don't become a Shaolin monk by just, you know, reading up on the kung fu
14:41
on the internet, you need to go to a monastery, live there for a while and stuff. Another thing, oh, okay, no problem. Another thing, but this isn't as a big of an issue as the discipline requirement, you need tools to do TDD
15:00
and this I will give you, so, you know, lucky you. As for implementation of those tools, I created a service, it's called Pydas, so a Python rewrite of DAS service and it's not German, it's Data Acquisition Service, one of our microservices, they are all open source,
15:22
by the way, yeah, so it was old, it was one of the first POCs and it kept running, it kept getting bugs, but, you know, the interface was well-defined, so I thought that, you know, this can be my, you know, my little guinea pig, I could test all my testing stuff
15:41
there and I rewrote the service, basically, using TDD, so it wasn't as crappy as the Java one, actually it was rather good, but, you know, from perspective of today, it isn't great, but, you know, it was educating for me, if you look at it and it's there, you know,
16:01
on GitHub, check it out, it can be educating for you because everything that you'll see implemented on the slides, shown on the slides, it's implemented in there. I've also decided to use Pytest in my tests because Pytest is great, it's concise, it has amazing thing called fixtures and you can compose those fixtures, use Pytest,
16:23
seriously, do it, please, or, I know, maybe there's something else that's great, but I don't know, so, yeah, I'll be sticking to Pytest. The tests, so, do you see this code here? Yeah, it's, this is how your service test, your functional test can look like
16:41
and it's rather, you know, rather concise, don't you think, it's, you know, has this definition, you see here a few fixtures, yeah, this is Pytest test, so, if you wonder what is the structure of the fixtures, you can see it here, this is our service fixture and this is DB fixture, this is the test, they depend on other fixtures,
17:01
but yeah, we will get to that later. But you know, this test can be pretty simple, you can just, let's say we put something in a database, then we just, you know, do a HTTP request on the URL of the service, yeah, some headers, because we are also testing authorization because we're going through
17:21
the whole application stack, we're gonna be testing everything. And then we do some assertions, so, you know, they look nice, I think. About the fixtures, I've used a trick here, you see, there's this DB fixture and it doesn't do much, it's just,
17:41
it's a function scope fixture, so, you know, it will get recreated on each test and it only yields stuff from here and then it does flush DB, which is this is, this DB session is a Redis client which lives for the whole session
18:01
and, you know, this might be controversial because I'm not recreating Redis on each service test, no, I'm reusing it because I thought that to myself, you know, Redis people maybe did their job right so I'll just clean it after each test and save a lot of time, you know, not having to create an entire Docker image
18:21
with a database in it. Also, of course, DB session requires a Redis port and where does the Redis port come from? Oh, from Docker, yeah. I just set up a Docker client, don't load the image if it's missing, wait for the container to start because, you know, you need it to be able
18:42
to start accepting connections. Then I yield the port back to the test and when tests are done, so after the whole test run, I remove the Docker container. So yeah, no trash after tests and if you're interested in the details of the code,
19:02
just check out Pytest. Okay, our fixture. This fixture will represent our services process, the whole process and you see there's the same trick
19:23
probably with the session version of our fixture so it will be that but, you know, long lived and we also have an external service imposter and this imposter is the thing that pretends to be another service and what do we need to implement those two things? We need mountbank, of course,
19:42
the thing I've told about earlier but we also need to manage mountbank in our Python tests. So I created a little library called mountpy and I think that it's rather nice. I use it in my Pytest tests and hopefully somewhere else in the future.
20:01
You can install it with pip, yeah, you know, you can go on the GitHub page, add some stars, you know, download it, play with it around, whatever and what does it do? It starts mountbank process, it downloads mountbank if you don't have it. If you have it, it will use your system mountbank.
20:20
If you don't have it, it will just download the binary package. It only works on Linux now but, you know, if you wanted to work on Mac OS or whatever, just, you know, put an issue or even better, create a pull request and, you know, when I saw that it manages the mountbank process,
20:43
I also noticed that I can use it to manage other processes. For example, this one of my service. So it also manages service processes. So anything that you can start on command line and serves HTTP, you can manage it with mountpy.
21:02
Okay, this is a big chunk of code but bear with me. So our service, what does it take to do? It has a command, you know, in the standard popen notation, so array of string. By the way, Waitress, yeah, I've been using Waitress.
21:21
So, you know, it's a WSGI server like Gunicorn or MicroWISGI or UWSGI as someone would call it. And here is, you know, calling mountpy. You just, you know, create a service object. You supply the command, then you supply environment variables because you configure your service
21:40
through environment variables. And you may notice this port thing here. Yeah, it's a notation that I've used in mountpy. If you don't want to fill out the port for yourself, you can just put this in and mountpy will give you a free port from your service, from your computer.
22:02
So yeah, you start a service, you return the object to test and then after those tests, you stop the service object. So, you know, no trash after test, nice. And the imposter, what is it? Well, we use mountebank to create the imposter. So mountebank is here, yeah, nothing interesting.
22:20
Create mountebank, start it, yield it, stop it. But with mountebank, we can create those imposters and I decided for them to be function scoped. So they are mocks. They remember what requests went into them. So you probably want to clean them out between tests.
22:40
So this can be useful. You know, this is a simple declaration of an imposter. So I just do, you know, some port on some HTTP path and this here will just, you know, return 200 for posts on this path. But you can configure it, you know, more precisely.
23:01
And it's the same trick with destroying it afterwards. So, okay, we have everything, right? You know, we have everything to create our legendary service test that will save our lives. But, you know, it's more than one test and it starts one process, another process and it starts an entire database in a Docker container.
23:23
So won't they take long? No, no, this is everything. So, you know, like three seconds. So maybe if you have tests that last that long, people will actually run your tests. So, profit. To be fair, when it has to download the Docker image,
23:43
yeah, it will take longer. And there's also this thing that when I run them on the first run after my machine boots up, it's like three times longer, I think. I didn't exactly went into why that is. But, yeah, it works.
24:00
Oh, and I, oh no, this is just pytest. We will get to talks later. Okay, a few warnings. If your service test screws up, a pytest will give you all the standard output. And you have output from like a few processes there. So you will get a lot of stuff. You will definitely know what went wrong,
24:21
but it's gonna be a wall of text. So be aware of that. And breaking a fixture. For example, my service fixture will also yield crazy big logs, but I break fixtures a lot because I tend to refactor a lot. And with tests, you can refactor,
24:40
and you should also refactor and sometimes bake your fixtures. It happens, it should happen, it's good for you. And even with those great technology of those masterful tests, they won't save you from human stupidity. For example, I prepared my pytest. I wanted to check if I can actually switch out
25:01
the old service for my new bright and shiny Python one. And you know, I've set it up in our staging environment, and it just kept crashing on requests. And why was that? Well, I had hardcoded localhost in Redis address. Because on my machine, the test would run
25:21
because you run those tests on localhost. And I just didn't notice that. So you know, they won't save you every time. Okay, so we have TDD. We have our wonderful tests of our whole application. So what can go wrong now?
25:41
Well, other people, because it's never you, we are perfect, of course. Other people can just don't give a shit about TDD and just, you know, crap out some code, put it in a pull request. It's now tests with 130 character lines,
26:01
with Java variable names. And it's bad. So what do we do with them? Well, we have few weapons against them. We have the test coverage stuff. We have static analysis, and we have contract tests. Sorry, I've almost drowned myself with a bit of water.
26:22
No problem. Okay, and we have contract tests. And you know, let's go over each of those. Yeah, this is my coverage, a short version of my coverage IRC from Pydas. If you don't know what it is, this is totally loop up coverage library for Python.
26:40
And I have this thing, and this might be controversial because I say that the tests fail if you don't have 100% coverage. And you know, why would you not have 100% coverage? You do TDD, right? And is this one piece of code not worth testing? Do you don't want it working? So if you don't want it working,
27:01
maybe just delete it. But you know, one argument that I hear from people is that you know, but if I want to have 100% coverage, I need to do those brainless tests that only just do mocks, and check if I call five mocks in a sequence because it's the glue code.
27:21
You know what, you don't have to do this because you have this, you have this, and this is one of the most amazing things in Python that I found in a while, and this is an option of the coverage library to allow you to get coverage from other processes. So you can actually get coverage from your service process
27:43
that serves a real HTTP request, and it can be added to coverage. Great, and if you want to check it out, how to do that, check out the Pydas and check out this documentation link. About status analysis, yeah, I've just put it into TOX. If you don't know, TOX is a great test runner for Python
28:03
you should totally use it, the link is down below. I just, you know, run my tests, check my coverage, and then just fire out Pylint. If Pylint finds anything, it's gonna give non-zero return code. The tests are going to fail, so if you have some bad stuff in your code,
28:24
the tests will fail. Yeah, I know Pylint isn't perfect, but if you're absolutely totally sure that you're not doing anything bad, and most times when Pylint says that, you know, seven method arguments are too much, it is too much, but if you're absolutely totally sure
28:41
that you have to do that, you can just add a comment, you know, Python, Pylint ignore, whatever. So yeah, that, and with that, normal crappy code before review, so more time for me, more time for you to do actual work. Contract test, yeah, where they are, kind of a big thing. They keep your interface, you know, in line.
29:04
And we have this wonderful thing called Swagger, and it's, you know, a language to describe the REST API. You see you have those paths, there's a get method, there are parameters, they have names, they have types,
29:21
or there are responses, for example, code 200, they have, you know, there's a type for the response, all of this stuff. Oh, by the way, you see here, here I have those little, you know, apostrophes, or whatever are they called? Yeah, you could just do 200 as an integer in Swagger,
29:40
but Python's YAML parser will complain about it, yeah. But what does Swagger give us? We can have the contract for our service. Contract is the thing keeping, you know, our whole microservice platform running because, you know, people have expectations about your services, and you have expectations
30:01
about other services, so we need to keep the contract tight. And with that, you can keep the contract separate from the code, because at times, you can do just, you know, somewhere, you know, two levels deep, three levels deep in some models, you're just, you know, you'll add some optional field. Actually, you've just changed your contract,
30:22
and your normal test may not pick that up, but it isn't something to be done lightly. So watch out for that. What are you going to do to do something with Swagger? We're going to use Bravado, which is a client from Yelp. Thanks, Stefan. And it dynamically creates clients for your Swagger service,
30:46
and it also verifies a lot of stuff, so, you know, parameters that go in, the things that are returned from the service, so you don't need to check the type, let's say, of the data objects that get passed. It's done automatically for you by Bravado,
31:02
and it's great. It also, you cannot do such thing like, you know, I've returned 201, I was supposed to return 200, but whatever, yeah, Bravado will beat you for that. But it's configurable, it doesn't have to be as harsh, but you know, whatever you want.
31:20
Usage, yeah, so in our service tests, we can just swap Bravado, yeah, client, Bravado Swagger client for requests, and our service tests now also double as contact tests. And you know, I thought to myself, but we shouldn't cover the whole API with service tests. It doesn't work that way. You should just, you know, use service tests,
31:42
like integrated tests for a few critical paths, but say you have another, like, quirky stuff in your API, then you should use unit tests for that, but it would be sweet if we could also verify them with Swagger, so I did a little library, because Bravado is extensible.
32:00
I've created an HTTP client that actually uses a Falcom test framework, and you know, for all web frameworks, like Flask, Django, whatever, you have those test framework, right, to do unit tests of your APIs. And I did a little library, you can also download it with Pip, and you can look at it.
32:20
It's used for integration of Bravado and Falcom, but you can look at the code, it's not that much, and you can do it with Flask or whatever. So now, you know, all our tests that touch the API are also contract tests, so pretty sweet. This is how the tests can look like.
32:40
You see here some imports. You do the client in the spec, spec is just a YAML file. Here you, you know, insert the HTTP client, the Falcom HTTP client that needs to be, you know, filled up with an API object. It's the same as app object in Flask, for example.
33:01
And you just, you know, you do a request. You don't need to worry about what's the path, because the client will know that. Here, you know, you specify the parameters, for example, the body here, and worker. Worker could be something like a path parameter, and Bravado will check all of that. You see here, you need to do a result, because the interface is also accommodating
33:21
asynchronous requests, but you know, there's a thing. And you just assert stuff. The service test, you know, you see, here doesn't look much different. Normally you wouldn't do that, you know, don't double the same test in services and unit tests. But the thing that differs here is that you still have a spec,
33:41
but you don't use a special HTTP client. Here I'm just using this standard synchronous HTTP client, but I need to give a URL right now, because this is a real service process that we are talking to. You can also specify some request options, additionally. Yeah, and so you know, like those are the contract test.
34:00
So now we should be fine, you know. Our service is taken care of. It's just working perfectly. It's 100% percent coverage. The tests actually check if the service runs. You know, we won't mess up the contracts by accident, so great, so our job is done. We can go home, right?
34:21
Yeah, no. This is just to do one microservice. And you know, in theory, all these things should run, because you know your contracts, you abide by your contracts, everything is fine. But the world isn't as simple. There are things you won't see in the future.
34:42
So we need end-to-end tests and exploratory tests for your whole microservice system. And they are hard to do, and I don't have the time to talk about them this year, sadly. So yeah, here are a few sources, and thank you.
35:15
No, nothing seriously? No, it's the read about the pin shows, so everybody wants to leave. Oh, by the way, two, I think, good talks
35:23
that relate to my talk this year. Hi, thank you for your talk. I was guessing if you tried, instead of using just Docker Pi, using Docker Compose in the unit test,
35:41
so it just rise up the whole infrastructure, and you can run your application inside a container? So, I mean, you may have even the same host name and the same replicated environment. Yeah, I could do that, but actually,
36:00
our applications didn't run in containers, so they just needed like one or two containers for them, so in the example of one container, it's easier to just do that. And the fixtures can do stuff like download. I think that Docker Compose can also download the images,
36:22
yeah, but it worked well in fixtures, and if I would want to use Docker Compose, then I would need to wrap Docker Compose in a fixture, because I didn't want people to have to do anything. It's just git clone, install Docker, install TOX, and just run TOX, and this is everything
36:42
that you need to do to run those tests. So, pretty sweet. You don't need to install Mountbank, you don't need to install anything else. Well, you need to install Python 3. Sorry. You're welcome. Anyone else? Okay, let's thank Michel, and let's go for lunch.