 Yeah, thanks for the introduction Mario Welcome, so it's a bit sad. This is one of the last talks at work in London. So I'm glad you're here It's an introduction into unit testing. So The talk will be packed with information, but also I aimed to have beginner entry level Knowledge required. So this should be doable at this second day last hour anyway, so Um Before we start with unit testing, let's have a look at three or two related things. So testing in general What is testing? This is the definition of the IST QB. This is the international software testing qualifications board. You don't have to read it And you should see the slides maybe Is that Okay. Yeah, so this is the definition of software testing in general. I highlighted three things here so testing is about planning preparation and Evaluation of our software and what we're interested in is if they specify with the requirements so if they satisfy the requirements and also um, yeah, the the Derek the direct goal is to find defects in the software So basically this is a test We have two things that should match and at this it doesn't matter What is the requirement and what is the product that we developed they should match and if they don't there is a difference And then our tests yet found the defect or the difference here And if you're wondering there are five differences here When we know something is there we might ask why is it there? Why should I care? Why why should I do something about that? So there are reasons for testing, of course One is software contains defects and they hide These defects may cause failures in our program Depending on what we're doing with our software these failures might even kill people and they definitely can cost you money so Testing our software gives us confidence in the code that we have so it's confidence in the functionality But also the quality so testing does not improve quality It tells you about the current quality and then you can do something about it if you have to But also when you test and you do it right and you're comfortable in testing with testing Then this might actually speed up your development process and there are other reasons for testing Last thing related to testing you know testing is testable code So if you think about it Every piece of software every code snippet is testable somehow So you could for example see what's the return value of some function? What's the output that I get there might be side effects like I call a function and some other variable in a global space or some Other whatever side effect can happen and also I start my program and it doesn't crash There's also some kind of a test And of course many more but this is not what when you read or her Here testable code. This is not what this refers to testable code is most probably always in the context of unit testing So it actually means unit testable code So unit testing is also called or can be called component testing or module testing and Basically It's just one part of the testing landscape So before we start with what is testing a unit testing we have a look at where it is so This is the V model. I do not want to tell you how to develop software. So this is just one nice overview of all the development phases or Things that you can do and will do in the process of developing software And as you can see This works. So unit testing is here and it has a relation to the module design Which is the component design the unit design and then the implementation. This is our software. This is the code and These things are related to each other So unit testing is dynamic testing of Individual units and you have to test them in isolation If you're sleepy, just remember this and then you're halfway good So let's now go through these three things step-by-step Unit testing is dynamic testing Dynamic testing means we execute our code In contrast to that we have static testing, which just means analyzing or reading the code Dynamic testing is really about running our software When there are defects in the software they might result in failures The failures have then one or more defects as the consequence as a reason or as The the the thing that produced this failure. So we want to debug them. We want to find the bugs We want to fix these bugs and then we improved our software quality and we started with testing our product or software Unit testing is about validation. This means we want to see if the requirements are satisfied And another phrase for this is are we building the right products? Another thing that has to do with testing with static testing is are we building the product right? And this is really about is this thing that we're building. Does it do what it should do? Unit testing is also white box testing. This is a technique or a collection of tech Techniques, I don't know and for testing. So this means Our software the code snippet that you're testing is not a black box to you actually white box is the most well-known Name for that but also it can be called glass box testing And this is really what I should I want to call it because you can see through the box and you see the code This means if you want to design unit tests you have to have knowledge about the code so Let's say this is a function. I have PHP and JavaScript code snippets and you can see if it's not obvious from the code itself You can see here in the right corner what it is PHP or JavaScript. So let's say we have this Function, this is our subject under test our function under test our testy, whatever and if we want to make sure That's this thing is behaving correctly or is behaving as expected Yeah, then we have first to know what is to be expected and in this simple case the expect the expectation is this thing Returns the string 42 no matter what you can do. I mean you could can just call it and this really return 42 Okay Defining units unit testing is about testing units. So what is a unit? When we start with our code so the atomic level we have in our code is a character Combining characters we can build words. These can be keywords values names. It could be operators and other things when we respect our syntax rules Then we can combine words into expressions words and operators and things like that and then Expressions can be wrapped into logic or they can create logic for example conditional logic mathematics and stuff like that When we want to wrap Different kinds of logic then we call this a function or a procedure and Even further we can encapsulate multiple functions or also just one function in a class or in a module or in a component And these things can also contain state There are of course other ways or other things other layers above that but Let's think about what we have So we have Characters we have words we have expressions we have logic and logic is the first thing that you can test so logic is something should happen for example if you Multiply one by two this should result in something this means actually something not by it by it on itself it's the combination of these things and also We can of course be because logic is contained in functions. We can test functions And we can test classes and so on Now going higher doesn't make sense because unit testing is about testing the unit and not only just one unit But the smallest unit that makes sense to test that is worth testing and that can be tested so as Of now we think about a unit either as logic or function or a class or module But let's think about logic again So in this example, we have three times logic. We have a conditional logic and we have two arithmetic expressions The problem with this is we can't test the logic, but we can't test the logic individually because You know The program runs from top to bottom at least for the first line and we will execute this piece of Software we will have this either result in true or false And if this is true, we will also execute this piece of logic and if this is false We execute that so we cannot test one piece of logic individually So this means you can test logic, but not as a unit so A unit is either a function or a procedure or a method or it's a class or module. This is up to us It's up to you now the third thing Testing and isolation. This is really important, but for some reason this is also very often overlooked Testing and isolation also means That you know the reason if a test fails Why that is we will see in the next minutes so Just your gut feeling is this here a unit test. This is taken from the WordPress core tests It's that a unit test who thinks this is unit test raise your hand Okay, it's not a unit test at least from what we can think of when reading this This is because We're having this function We're having this function and this is from the name actually what we want to test But we also call this function and again and another function. So this is not a unit test This is some kind of integration or system tests, but it has every right to exist It just should also be accompanied with unit tests so For the remainder of this talk, I will show you unit tests Code examples and then the unit test and tell you why we can come up with these kind of tests. So the first thing is These two PHP and JavaScript versions of the function that we already saw before so When we inspect that and see what we're having what we're having here Basically, we have us. We have a simple function. We don't have any dependencies And to test this function all we need is to have some kind of test framework a test runner a unit test framework These are just a few for the PHP side. I think PHP unit is the most well-known of course For JavaScript, there are really really many not as many as libraries, but there are many I think just is in the last one and a half or two years the most Well-adopted if you start testing right now and also I saw a lot of people move from some whatever they had in the inner In an old in a running project not when they started your new project. They actually moved all their tests to just Um tape is something that I have been using before because it's really really simple And it doesn't give you all the bells and whistles and you have no idea what to use when So an example unit tests here remember the function just returns the string 42 So we have an expectation The expectation is we get some value if we call that function and the value is 42 Why do we know that because we have to have knowledge of the code and it's written in the code So it's 42 Then we call the function And then we assert or we want to make sure that the expected thing is actually what we get It's as simple as that the JavaScript version. I'm using just here is pretty much similar So we have an expectation we call the thing and then we compare these two things Now what happens if we do object oriented programming? So we have the function from before but we encapsulate that in a module or in a class So what's new here is we still have that simple piece of code the function living in some module We still don't have any dependencies which means we are still good with just a unit testing or a testing framework and This is from before so in the next code examples I do not have expected an actual separately because it doesn't fit on the slide anymore So we have an expectation and we call so we create on the fly an object and directly call that method And we want to make sure that these two things fit together This is a JavaScript version the third example What's new here is we have So basically there are many things There are a couple things new differently, but they might not have an effect on how we can test or how we have to test so what's new here is when we Just have a look at the function. We taken some input and Then inside the function we might have or we we depending on the input We do have two flows of the code So either this thing returns the answer of Oracle and we have a look at this in a minute or an empty string So Oracle is something that we feed into our class. It's dependency injection It's something from the outside that's being injected into this object and we're just using that What's important for unit testing here is we have no idea what this thing will return and we're not interested in that We just want to make sure that if we spend enough money that we return the answer of that Oracle This is the JavaScript Equivalent it's pretty similar here in the PHP part. This is actually PHP 7 and beyond code So we have type hints scalar type hints as well and in JavaScript We do not have it so we have to cast it and Yeah, the logic is pretty similar So once again when we inspected we have that conditional Logic and we have that Dependency external dependency. So what do we do with that? I told you that you have to test your units in isolation But I did not tell you how to do that. So how can we test something in isolation if there are dependencies? Depending on what? Material you have like videos or articles or books what you have You might read about mocking you might read about stubs. You might read about spies fake dummy objects Whatever it's pretty much always referring to something That is just a dummy piece of code which you can control if you want or if you have to So what we have to do or want to do here is two things We have our piece of code and we want to execute that because we're doing dynamic testing This means we do not want to have any errors here Which means that if PHP the parser finds something that's not there we will get an error So we have to make sure that this thing can be ran But also we do want to have all the dependencies being fake ones that we can control So again, we have this conditional thing taking input and also we have this dependency So what we're using in addition to the testing framework is a mocking library Depending on what you use for testing framework. This thing is available in the testing lab library itself For example PHP unit has built-in mocking capabilities just as well But you can use something additional for example mockery or prophecy for PHP I don't list JavaScript because in JavaScript we can just overwrite anything that exists in the global scope in PHP You cannot do this that easily So this is one way to design the PHP test The first line is just so I'm using mockery here and the first line is just to make that integration with the PHP test runner and my mocking library and the test method itself is first of all, let's start here. We're instantiating an object of the class that we want to test and Then we call the method with zero amount of money, which is Not enough because we want to have five or more and the amount 100 which is enough So we expect the empty string in the first case and If we spend enough money, we expect some answer. Now, what is this? Answer is in our tests just a hard-coded string and Then we create with mockery an object that has an answer method So you can call answer on that object and it will return you the value stored in answer So if you think about that we Feed this oracle thing It's just a fake object to our fortune teller if we spend enough money This fortune teller should ask the oracle should ask should consult the oracle and we define how this oracle thing Should behave in our test. So we tested Fortune teller in isolation or not really in isolation, but we did not test any other real thing Which might contain defects As you could see in the example before we had two times Pretty much similar calls like we expected something we called the method and we passed some input and sometimes you don't have only two But even more so when you use PHP units, you can make use of something. It's called a data provider the data provider results in our Test methods being passed some arguments that we define later on it's here on the next slide And then we just take this thing that we get passed as an answer and then we take an expected value that we could also pass and we Put the money that we could also pass into the object So what you do by using a data provider is you make your test methods pretty simple And also you separate the test method itself the test logic from the configuration of that Like what are you testing with the input and expectation values? This is the data provider in this case. I just have two different test scenarios One time I spent zero money and I expect the empty string and this is actually not being used So this is the result that the oracle should return But this is not being used in that case if I spend enough money the expected answer is the answer of that oracle Using JavaScript, it's pretty similar and Here we don't have data providers, but there is an additional library that's called just each And when using this you have an array of the input values and then you call the simple test method and In this I'm passing this oracle thing and this doesn't change So in JavaScript, I can easily create this out of this thing because it has it has nothing to do with what we feed Our testy it should always behave the same Okay fourth example Um It's pretty similar to the example to But we call a method a function. Sorry. That's not defined here in our code itself So in JavaScript, it's a global function in PHP. It could live in some namespace or whatever So what's new here is we have this external function and If you know PHP, it's not easy to just redefine a function or simply it's not possible to just redefine a function For JavaScript, it is possible But still you can make use of dedicated mocking Redefinition libraries for PHP. It is for example brain monkey or patchwork, which Is being used by brain monkey under the hood but brain monkey allows for other things that you will see So I mentioned that here and for JavaScript. You can have you can use just mock or sign in JS This is a possible PHP test So what we're doing here is I'm pretty similar to before we define a function not an object We define a function And we tell the function how to behave so this should return answer Which is just this hard-coded string the assertion is pretty similar to before But also what this allows if we want to do this we can make sure this this thing This function should only be called once and exactly once it has to be called but only once and also Only if these two Arguments are the values that's being called with then this will return The hard-coded answer. I think by default. It's null or something else empty string. I don't know and The arguments that we pass in here are up to us So I could also pass the m the hard-coded string in the first place like the answer is 42 for example This is up to us. Is this really important for the functionality of the code or not? This is a JavaScript version We have this Function living in an object living in an object living in the global scope So what we have to do here is in our test We have to make sure that this that is there. So we just define that and we use just to define this function and This is important when we're done We have to reset that because this might affect other tests that we're running later on and Then the test itself is pretty similar to before so we call the thing and under the hood it's been using our mocked function and Also, we can make sure that this function is being called once and in this example I actually did not have this regex or some string or whatever I passed in the answer is 42 dot So this is up to us Five things a fifth example is Basically It is just like before so we have additional functions. We have to action. We have apply filters So we could just mock these two functions and decide how they should behave For WordPress these are two important functions if you're developing a plug-in you should make use of these two functions It's the plug-in API the plug-ins API. So Some nice guy and former colleague of mine developed or created a library that Can be used for mocking WordPress related functionality so with this Library is brain monkey and there exists another Pretty similar and library WP mock with this library. It's possible to write code like this. So this is our test code We create an object. We call the methods and we directly can expect something We did not specify do action and we did not specify apply filters This has been done by brain monkey for us because it yeah This is this is thought to be used for plug-in developers and theme developers and Also in our tests we can call this function and what's important here is this is not the WordPress function This is also been set up for us by brain monkey it behaves exactly like like the WordPress function and allows even more and also WordPress does have did action, which just means Give me the number of times the action hook with that name has been Done in WordPress terminology In WordPress, there is no dids filter or applied filter brain monkey has this for us It's a static. It's it's a function living in this namespace. So we can also make sure that the filter has been applied once six and seventh examples are JavaScript a Bit more state-of-the-art So This is code Involving JSX so we might want to use react for example what this thing does is We create basically a list item With data that we pass in an ID and a text and then we create it so What you see here is we have JSX We do have props that we passed We have no really dependency except for react that we need to be able to yeah, interpret JSX code Which means we might want to use or we have to use a react testing library for example one of these three then Our tests could look something like that so Here is the thing that we can create with the function from before it's actually a component It's a simple stupid component We pass ID which we set up here We pass text which we set up here and then we use something from react test renderer So we create something from that JSX expression Then we create a json expression from that and what we can do then is for example we can make sure that the type of the Node or the HTML elements that this JSX expression renders into is a list item We can make sure that this thing has a class name oracle answer We could for example test that ID is somewhere in the children. It is just in a text node and so on We also have this text here and if you remember we had text wrapped in the em Emphasis Emphasize HTML tag and so on and this is unfortunate because this is still JSX inside here and you cannot easily Test some regex magic here with JSX But there is this nice thing called snapshot testing so what this does is it just renders the whole HTML for you and That's it for the first time Every other time then we that we execute our test methods This thing will get rendered again in memory and Compared with the result that we store in a file So the result of that snapshot is being written to file somewhere And then if for whatever reason on some call of our test method This does not match with what we had before and what we wanted to have then we yeah, we get Screamed at so that's something wrong. Please check this This is for the simple example what the snapshot file looks like so we only had one One one export case one scenario in here. So we caught this thing with two values ID and text some ID here some text here and this is the rendered HTML and Again if we call it again and this does not match then yeah, we have to check why that is maybe We added some class here. Maybe we do not want to have the colon But we want to have space dash space whatever it's up to us to decide if you want to update that or if there's actually Something wrong in our code last example This is again a react example It's not a stupid Or it's not as stupid as before because what's new here is that we also import some other Component before we just rendered html so existing html Elements now we also have this answer thing. This is from example six so our react oracle Reads an array of answers and then creates a list with each answer being a list item that you saw before So we have JSX we have props we have also dependencies so one other component And if you remember we want to test this in isolation. So we still use a react testing library But we have to do something about only using our unit that we want to test our component in this case Luckily, there are different testing libraries that have this built in for us. So For example enzyme in this case. I could also use the react test renderer from before. I just want to show you different things Enzyme has a function called shallow for us What shallow does is whatever JSX expression you feed it as soon as the function Reaches something that is not an html an existing html element, but another component This is not being interpreted it it stays just as it is so for example as you can see here We call our testy Sorry, this should be react oracle with this array of answers that we created here before like just two objects We have an ID. We have a text and Then we shallow render this The first expectation is this thing should be an unordered list with a class oracle and Now we loop through all of our answers. So to in our case Take this is destructuring. We take these two properties. So in the first time we have this object We take ID we take text and now inside of this function We have these two variables and now we make sure that's the wrapper. So this is the whole output that we have Contains an element that is still answer. So we do not want to interpret answer But we know it's there because we know the code and we have to know the code and we also know that ID has to be passed and text has to be passed actually all the props that we passed But this is what we're interested in and now we loop through this. So actually we have one two three expectations Okay, so we saw seven code examples or actually 14 12 15 something like that because of JavaScript and PHP So how do you write unit tests and how do you write good unit tests? There is a great article by Eric Elliott Which basically says that every unit tests has the the task to answer five questions The first one is what we are testing The second one is what should it do? So this is really what we expect here the third one is Sorry, what what should it do? Yes, and and what is this is wrong should be actual. Sorry. What is the actual result here? Okay, it's this way. Okay, so we still have expected an actual And then also of course because tests are some kind of documentation. It's important for us to know how we can reproduce the test So for PHP this is a simple template for that so we have the what Split over here the what class and the what method This is what it should do. So for example return 42 or return the next best thing Or I don't know something that makes sense for you in plain English Then we have the expectation Then we have the actual result and also PHP units in the assertion a method that it has Allows you to for every assertion Specifies some message that if this thing fails you will see in your output. So this is again What should it do here if you want to use it here as well? So where's the fifth answer? It is also the actual thing It is basically what we have here and everything that's related here So if we call a function with some argument that we set up before all of this is how we can reproduce the test This is the JavaScript variant So we're using this describe and test or if you want to describe and it Functions here what we're testing. What should it do? Expected expected results actual result and this is also what we define here how to reproduce so The takeaways from this talk. Hopefully our unit testing aims at finding defects. We're on a code level here It is about executing the code. So it's dynamic testing We're testing units per unit, so we're testing them individually and We have to have full knowledge of the code And also the result of this or the the actual implicit goal is yeah We want to make sure that the software works If you want to read about that the slides are online These are articles about unit testing and now I guess there's maybe Time for some questions if you're still awake Thank you This depends on your testing library for example PHP unit has expectations for output So this under the hood calls or uses output buffering and you can just yeah Create some expectations against the output. It's possible Yeah Any further questions? Mm-hmm Yeah, so if you want we can later on meet somewhere I can show you so you mean more PHP or more JavaScript or both Yeah, yeah, sure. Yeah, yeah Um, do you want to have OOP examples or I think I only know good OOP. Yeah. Yeah. Yeah, sure It's late when you create a snapshot Can you sort of pre sanitize it to cater for different reasons different results for example dates down? So Something like that I'm not sure what you mean with sanitize because it depends on What the actual code is that you're executing and then if you want or if you can manipulate that because if you if your code Creates a date timestamp, whatever then this is what this thing should do Yeah, I might not care about the timestamp itself. It's the other data. It's more important. I Mean there are different ways to use these snapshots So for example, you don't have to create one snapshot from the whole thing that you unit is you can Create snapshots from everything that can have a string representation So for example, you can create a snapshot from a JavaScript object You can create a snapshot from just the string or something like that So you don't have to use snapshots only and also they don't replace unit testing they give you For some components or for some things that you want to test they give you this nice thing that you just want to execute Check it once so check the snapshot file if this is what you want Then you don't have to do anything Until the testing library says hey, there's something wrong. Please check and It's up to you to decide if that makes sense and for what kind of data that makes sense or not