 Thank you. Good afternoon everyone. So as mentioned, I have been using WordPress quite a while. Last few years I have been working mostly in enterprise environments, with large code base that requires a lot of approval process or code reviews and some pipelines to be, requires some pipelines to be executed before the code reaches the production. So I'd like to share some of the knowledge I gained during that experience regarding testing WordPress plugins. So I'll be going over what is unit testing. I will briefly talk about some benefits of unit testing I'll show you some tools and setting tools and I'll show you how to set up an environment for running unit tests and show you how to scaffold the test suite for plugins using WPC-LIN. I'll do some quick demo of writing and running tests. So then at the end I'll show you some links or advices where to go for learning more. So what is unit testing? It's a software testing method and it verifies individual units of code. Those are mostly functions and it makes sure they are working as expected. So in most cases you just run some function or the method of an object and check the result. If the result is same as you expected result, if it matches your expectations. So the ultimate goal is to ensure that behavior of that function stays consistent. So it doesn't change when you do some refactoring or do some additional changes to your code. So there are a lot of different benefits of unit testing. First of all, it's better quality. As you start testing your code, you will notice that the quality of your code starts to increase and also the testing with unit tests allows you to test to be more granular, to go more granular level than point and click testing with graphical user interface. So usually what you do if you don't write unit tests, you just go to the plugin page or some admin screen or the front end and just click around, try to go to some link or click the button and see the expected result. But with unit tests you go much granular level. You can check out the code bases of large and very popular plugins like Jetpack or Yoast SEO and see how they are running their tests too. All of those large plugins, especially popular plugins that are used on millions of websites, they all have some kind of automated tests to keep the quality consistent. So once you have a test suite, refactoring your code becomes much easier and you will have much more confidence on updates you introduce to your code base because you will have a safety net as a test suite that will catch your errors if that happens. For example, you can change your function since the result stays consistent and you can ensure it by running your tests. It allows you to debug faster so if some kind of bug will happen in your code after your changes you will quickly catch it by running your tests. And you can also add additional tests to make sure that error does not happen again. It does not occur again. And tests can provide some documentation to your code too. So you can read the tests and by reading the tests you can see how that particular part of the code should behave because tests will check the behavior of that code and expect the results of that code. And you can also use those tests to design your code too. That's known as TDD in software engineering, test-driven development. So in this case you write tests before you write your actual code. You can start writing a test for the code that doesn't exist yet. So that test will of course fail but once you see that the test is failing then you fix that failing test by implementing the actual code. Anyway, you can design your code. You can decide on the name of the class, name of the method, what kind of data that function should return, what kind of argument that function should receive. All those things will be designed while you write your tests. So what do you need to start testing WordPress plugins? So to do that you will need a Unix-based operating system. It's very hard with Windows. If you use Windows, don't even try. But there are ways, you can run of course. There are some workarounds. You can find some workarounds on WordPress Handbook too but I find it best of time and sometimes it's not very consistent. So the Unix-based operating system, PHP of course, MySQL, PHP unit, the testing library, and WordPress Test Suite and WPC-LI which is optional. You can write those tests yourself but also you can use WPC-LI to scaffold the first tests. If you manually one by one install all these tools for newcomers, for someone new in this area, it may be a bit hard or they may stack at some point. For example, there are different ways of installing PHP unit. There are different ways of installing MySQL or MariaDB and also WordPress Test Suite also. It's not really always easy to install and set up. So if you need already set up environment, I would recommend using VVV. It's a varying vagrant. It's a pre-configured virtual machine and it's recommended local development environment for contributing WordPress core to. Yeah, you can find more information about it on the website but basically it's a virtual machine that has all the tools installed and you can run it on Mac, on Windows and you can run your tests inside that virtual machine and run your, of course, all the websites and all your code too. So it comes with a bunch of stuff and it has all the required things for starting to test your plugins. So as I mentioned, you can start building your tests with it manually. You can start building your configuration files and start creating your PHP files with tests manually but WPCLI comes with a very handy command that allows you to scaffold the initial tests very quickly. So I recommend starting with that if you want to implement a test suite for your plugin. So the command is very easy. WPCLI tests and plugins name. You can learn more about it on the handbook of WPCLI but what it does is it just creates some boilerplate to start testing your plugin. So I will do a quick demonstration of this command. Before that, I just have one simple plugin that I will be using for this demonstration. I just want to introduce you what this plugin does and what kind of files it has. So basically, it's a plugin that adds a widget that displays some stats about the website. The stats are very basic. It shows just the number of published posts and pages. So the main plugin file requiring three classes and initializing the plugin class then running its init method. So under the PHP folder, I have all these three classes. Plugin class, stats class. Stats class has get side stats which returns those actual stats. And the widget which extends WP widget to display all this data as a widget. And I have a template that has an HTML code of that widget itself. That's it and readme file. Visually, it looks like this. So plugin on the front end. This is how it looks like. Side stats, number of published posts, number of published pages. That's it. So if I add one more post and publish it and go to the front end, you see number of published posts are now two. So I will be using this plugin for demonstration of these tests. So I'm inside the VVV, my virtual machine. I just went to the plugin folder and running that command WP, scaffold, plugin tests, and the plugin's name. Simple, side stats. Say success, created test files. So let's see what it created. It created these files in red. This XML file, this file, the YAML, this configuration file in XML. And it create this test folder inside this bootstrap PHP, a test sample PHP. And this bin folder, it has a bash script. Let's see what they are. PHP unit XML, this is a configuration file for PHP unit. It will have all the configurations needed for your test suite. And the bash script under bin folder is a script for configuring the WordPress test suite and the test database. And bootstrap PHP is a file that makes the current plugin active when running the test suite. It bootstraps WordPress core and then adds your plugins code to its plugins folder or activates your plugin, and then you can start testing it. Test sample PHP is a sample file containing the first actual test. And two other files, PHP CS XML disk and Travis YAML are optional in our case. We don't need it. But they are very useful. I would recommend to take a look at them too because PHP CS XML file is a configuration for PHP code sniffer, which allows you to run linting to test your PHP code with its compatibility with the WordPress coding standards. So it makes, if you run PHP in the code sniffer, it makes sure that you are following WordPress coding standards. If you are, for example, have some issues in your code, it will warn you. Travis YAML file will allow you to integrate with CI continuous integration system. So you will have already configured file for Travis if you want to integrate continuous integration system to your code. But we will not be doing it. It's out of scope of our presentation today. But those are very handy configurations to bootstrap the process of continuous integration. Let's get clear view of PHP unit, XML disk file. So the main important part is this test suite part. So you can have multiple test suites. In our case, for this simple plugin, only one test suite will be enough. But you can divide your test suites if your test suite becomes very large and then you can run them separately. So directory text says that it has a property of prefix and suffix, which this means is it searches your tests inside the test directory. And it checks for plugins that start, it searches for files that start with test dash and ends with dot PHP. So if you add a file with a name that starts with test dash and ends with PHP, it automatically adds them or runs them when you run PHP unit on the console. And it's excluding this file for now here, so it will not run that file. Even it meets this criteria. And the bootstrap PHP, as I mentioned, it's bootstrapping here, like getting the tests through environment variable. It searches the WordPress test suite in that folder. And then it includes those files. If it cannot find it, it shows an error message. Could not find the PHP file. Did you run bin install wp-test.sh? That's the bash script that WPCLI generated for us. So that means you need to run that bash script if you want to set up the environment. But in our case, we are using VVV. That's why I will not run that bash script. But if you want to set up, like, testing environment in custom Unix box, you will need to run that file. So then it, as I mentioned, it requires that functions PHP. Then loads our plugin. Simple site stats PHP. These environment variables are very important. wp-test there and wp-core there. If you echo them on the console on VVV box, you can see where they are located. So this is the location of the WordPress test suite. And the second one is the WordPress core that you will be using to run your tests. And that bash script downloads the required WordPress version, installs the WordPress test suite, defines those two variables, creates the database for tests, and basically prepares the testing environment. Again, as I mentioned, you don't need to run it in VVV because it already has all the environment. But running it is very important on, for example, if you set up continuous integration pipeline, you can see that in the Travis YAML file too, it will run this file and prepare the testing environment first. You can test your plugin with different versions of plugin, with different versions of WordPress and with different versions of PHP. So which will ensure your plugin's compatibility with different versions of PHP and WordPress, which is good. You can see it on the code basis of, for example, the OCCA or other popular plugins that you can see that they test their code with different versions of PHP and WordPress. And the main important file with test is test-sample-php. It will have only one function called test-sample. So I'll go over what it does in next slides. So if you notice, this class is extending WPUnitTestCase. WPUnitTestCase is a class defined in the WordPress test suite. And it extends the TestCase class of PHPUnit. So it adds additional functionality to PHPUnit. So it includes additional functions and assertions useful for WordPress. And if the term assertion is not familiar with, you are not familiar with that term, I'll define that in the next slide. So we'll see that. Don't worry about it if you don't know. So WordPress tests should inherit from this class because it adds additional functionality to your tests and you can use it. So what is a test? Test is any public method inside that class that inherits from TestCase class of PHPUnit or PHPUnitTestCase. And it must start with a test underscore prefix. So if your methods name starts with test underscore, then PHPUnit will count it as a test and execute it. If you don't like it, you can also use addTest inside. You can mark the test method with addTest in the doc block. And that's another way of defining the test too. Here you can see two different methods. One starts with test underscore, another has just addTest in the doc block. Both are like tests. And when you run PHPUnit, these methods will be executed. Now assertions. Assertions are methods just like this. Assert true in these test methods. Assert true, assert true. And they are used to assert that actual value matches the expected value. So with these methods, there are a bunch of assertion methods available with PHPUnit and WordPress, TestSuite, and SedationalSum. Like assert true, assert false, assert equals, assert null, assert contains, assert string starts with. So you can see the full list on PHPUnit and its documentation. But what I mentioned are some of the very frequent ones that you use. In this slide also you can see some samples, like assert and testing. Here you see the stack is empty array, and this method will assert that if it's empty. If it's not empty, it will fail the test, and you will see that on the console. Here's some sample code, like very simple class. Add method and subtract method. Add method receives two arguments and returns the sum of them. So it just adds two numbers. So let's see how the code that tests this method looks like. So you write another class. Notice that its name is different, of course, test calculator, but you are free to name it as you wish, like it's not important. But it should extend the test case class. And we're adding a method called test underscore add. So it should start with test underscore if you want to execute it. You can have different other methods, too, but only the ones that start with test underscore or as an add test dot block will be executed when you run PHP unit on the console. So what this method is doing, it's initializing the calculator, it's creating its object, and then this assert equals, using this assertion method, we are asserting that if we run add method with arguments two and two, the result will be equal to four. That easy. So that way we are testing if the method is working correctly. So if it doesn't, then this line will fail and show you error message that shows what was the expected value, what was the returned value. You can have multiple assertions. You can test with, for example, negative numbers. You can test with, for example, decimal point numbers. So you can have multiple assertions in your test method. With WordPress plugins, of course, usually your methods do not look like this add method. It's not that simple as adding two numbers. You usually use different WordPress methods. It's tightly integrated with WordPress. You run a lot of different WordPress built-in functions like add action, add filter, you create some posts, add metadata to different posts or read that metadata. So it's very integrated with WordPress. Another type of the tests are called integration tests. They are basically same as unit tests, but they are not isolated to one method only. Unit tests do not write to database or read the file, but integration tests can. They can write to a file, they can open a database connection, write to the database, read from the database, do something over the network, run some WordPress methods, et cetera. So with WordPress, you usually write integration tests, but basically they are same as unit tests that we reviewed a bit earlier. So I'll try to do some live demo. Usually things can go wrong during these live demos. There will not be a lot of issues, but I will do some un-proposed mistakes, too, just to show you how the things work. Let's do it. So first of all, before doing anything else, I would like to try to run that first test we have, this test, test sample assert true. So what's it doing? It's just dummy assertion. It's just testing if the true is equal to true. True is always equal to true. So it should pass it. This test should pass. So like to run this test, I run PHP unit on the folder where the PHP unit configuration file, that XML file is. It's basically the root folder of our plugin. PHP unit, hitting enter. It sets up the testing environment and it run and at the end you see that no tests executed. Why? Because if you notice in the configuration file, PHP unit XML, this file was excluded. So this is not un-proposed. So you didn't run this sample test with your real tests. I will remove this exclude from the configuration so that test file is executed. It matches the criteria, right? The file name, test-sample, it has a test-prefix and it ends with .php. So we should be good. So let's run it. And here you go. One test, one assertion and it passed. Okay. Let me show you how it would look if it failed. Assert true, if I put here false and run it again, it will fail. It says that failed, asserting, that false is true. Okay. It's working. But we don't want to do this. We don't want to assert true. It's equal to true, but we want to test the real code. Let's test this GetSiteStats method of the stats class here. It's the main functionality of this website, this plug-in, if you notice, it's returning those stats. So it's returning an array with post and page keys and it gets the stats from WP count posts method of WordPress core and this function returns an object with number of posts for each status. For example, if you pass here post, it returns an object with number of published posts, number of posts in the trash status, number of posts in draft status, and same for page. So like first thing we see is it returns an array. Let's make sure this function, this method returns an array. So to use this function, I need to create the instance of the stats class. So stats is equal to new stats and then let's get the result of it. SiteStats is equal to getSiteStats. Now we can start writing assertions. What do we want to make sure? It returns an array. So this assertTrue is an array, this is PHP function, SiteStats. So this is easy. We are asserting that this SiteStats is an array. This array returns true if this SiteStats is an array. So saving it, running the PHP unit, it passed. What else we can test? We can test that array contains those specific keys. So there are some assertion methods for that this. Assert array has key and key's name. It must have a POST key and page key. Remember the function? It returns an array with POST and page keys. So let's run this again. Now it again passed but see, three assertions was that. One test, but three assertions. So we can add more tests. For example, let's make sure this getSiteStats method returns actual number of posts, like zero, one, or two, or three. We want to make sure it's working correctly. Before doing that, I just want to quickly do quick refactoring here. When the test is working, this file doesn't look good. It still says sample test. The method says test sample. It's not a sample anymore. It's real test in our test suite. So let me change the class name, from sample test to test stats. I'll change it here in the doc block too. Let's give some meaningful name to the method to test if getSiteStats returns an array. In the doc block, test for the getSiteStats method. You can do C doc block and give some reference to where the getSiteStats method is. It's inside the stats class. The method is this. So, did you notice it's adding this namespace everywhere? To get rid of it, I can add this class to the namespace we have. Simple site stats. It's inside this plugin. As soon as I add this, this will not be available. I need to start from the root namespace because it's in the global. This class is not inside our namespace, it's in the root. Now I can get rid of this because we are already inside our own namespace. Pretty much better. And also, I want to rename this file testSamplePHP to testStats like per WordPress coding standards. Your class files must start with class prefix and class test stats. Now the file name is classTestsStatsPHP and the class name is TestStats. I think it all looks good now. Let's try running the PHP Unity game. It says no tests executed. Any idea why it happened? Why it's not running? Our tests? That's right. Good catch. In our configuration, PHP Unity XML file, we have a criteria for the test files that those test files must start with test-prefix. We did the class-test-stats so let's add class here too. That means all files that start with class-test- will be executed as test files. So go back to console and again we are back. One test with three assertions. Now we can add one more test. That's the actual test of the numbers. I'll just copy-paste this part. I'll just copy-paste this and create another test method. Of course, we'll name this TestIfGetSiteStatsReturns correct numbers. Again, I need to create its instance around the method and now let's start testing this assert equals so when I run the GetSiteStats what will be the result number of posts in the empty website? It's going to be zero, right? We don't have any posts yet. So I want to make sure this siteStats post and we are testing published post publish is equal to zero. Running it, it passed. Same thing for page tier. This is making sure the number of initially without any posts. This like method is returning zero number of posts and zero number of pages. Now, how to make sure this right now, we didn't create any posts in our system, in our testing environment. There is no posts or pages, that's why it's returning zero. How to make sure this works with existing posts or like returns correct value when there are some posts. So you can create you can create some sample posts inside test suite inside your testing environment. And this class WP unit test case allows you to do that. There are some factories that allows you to generate some posts pages or some taxonomies, taxonomy terms users inside your test environment. That's called the factory method. So this factory post create and you can pass the post type here. Post is post. So what this method does is it creates a new post inside your testing environment. So let me create sample posts we created three posts and one page and now we can assert again so what's the number of posts now? Two and number of pages is one. So run it it should fail. Why? It says there was one error argument two should be an array inside correct numbers. So that's publish publish. I did here the post type. Sorry? Yeah, that's right. This must be a array. Good catch. Let's run this. Now it fails again. Now it says better message asserting that zero match is expected too. So somehow side stats post publish is still zero because this method was executed before we created the post. So I'll just run it again to get the fresh data from the database and now our test should pass. So that's how you test it. Your WordPress plugins. You write these kind of tests for each part of your test and each part of your code and test it if it's behaving correctly as expected. And yes, in a conclusion I can say that it's hard to get started and you probably notice that and you need to motivate to start doing this and it even may seem pointless why you're writing all this code but in the long term you will see those obvious benefits that I counted in the beginning of my slides. So as soon as you do first refactoring to your code having a test suite inside your code base you will see that benefit. You will see how it's catching your mistakes how it's catching the problems occurred after you refactored your code and from there you will see those obvious results. Then at some point you may start doing TDD writing tests before actually writing your code which is another level up. To learn more you can check out the code bases of those popular plugins. You can check the code base of WordPress core to WordPress core also has a lot of different tests. Learn more about PHP unit assertions and there's a good series of articles like PHP unit on mock objects, stop methods, dependency injection I would recommend reading those articles too. These are more once you start testing you will be at some point stuck on questions like how do I test for example API call. So you don't want to run the API call with actual keys and credentials you can mock that calls and create mock results and then test your part of the code and don't care about the API and those kind of things. Thank you. Do you have any questions? Yes? I didn't install the PHP unit here but you can install PHP unit in any like method you wish. So actually installing it with composer is a good idea it's a commanded way because PHP unit has many different versions too. VVV is like dedicated for WordPress only that's why it already has the correct version of PHP unit but if you want to run it in some ways and if you want to control over the versions of course installing the PHP unit with a composer is a good idea. You can of course install it with a composer and run it from vendor folder so install it with a composer and run instead of PHP unit you run it vendor slash bin slash PHP unit and it works same way. For that you have to run that bash script that was generated by WPCLI and that bash script will pull WordPress core, WordPress test suite and creates required tables in your database and sets up those environment variables for running it and prepares your environment and you can see it in the Travis YAML file generated so when the test suite is executed in this other server with Travis continuous integration system everything must be manually set up so you can see that it runs the bash script it runs the PHP unit one thing about the PHP unit, the latest version of PHP unit is 7 but WordPress core is not compatible WordPress test suite is not compatible with it yet so you should use PHP unit version 6 for running WordPress unit tests. Other questions? Well if you have any other questions maybe later you can always find me here or you can find me in many different places I'm at Behzad my first name it's one of the benefits of having a rare name you can find me on Twitter you can find me on WordPress or GitHub I did a similar presentation earlier this year in San Diego I see the short here from San Diego it's recorded you can see that it's more introduction so there I showed how to do this for new plugins so you can generate scaffold again and start writing tests for it so some of the slides from this presentation are very similar thank you