CAll Us: +1 888-999-8231 Submit Ticket
Git Hooks – Hostdedi Blog

Git Hooks – Hostdedi Blog

Git is a powerful version control system that we’ve barely scratched the surface on over our last few posts. Today, we’re going to look at the automation power that Git can give you with Git Hooks.

Every repository gets hooks built in when you use the git init command. When a repository is initialized you get a hidden .git directory and inside that is a directory called hooks that will contain all your hooks. Open any git repository you have handy and use ls -a to see the hidden directory, then open it up in your favorite code editor.

To start you’ll see a bunch of files with .sample file extensions. These are exactly what they say, sample scripts that you could use in your projects. The files are named to correspond with the hook they run on. So post-commit.sample runs on the post-commit hook.

You can use pretty much any language to write a hook. The file is parsed according to the shebang notation at the top of the file. If you wanted to use node you’d use #! /usr/bindi/env node and your file will be parsed as a node file.

Before we dive into what you can do with git hooks, let’s take a look at some of the hooks that are available to you.

Types of Git Hooks

Commit Workflow Hooks

pre-commit is run before you even enter your commit message and it can be bypassed with git commit --no-verify.

prepare-commit-msg can be used to edit the default message you see in your commit message. Use it to give instructions to developers about what type of commit message they should be leaving. It can also be used to automate the contents of where the message is automatically generated for you, like merges or to add an issue number to your commit message automatically.

commit-msg can be used to validate the commit message for your project. Maybe you don’t want anyone to be able to put in a commit message that simply says “dealing with white space”. You can use this hook to detect the presence of the words white space and then exit and provide a warning to the user that they need to have a better commit message.

post-commit runs after all the commit hooks above. It’s most useful for a notification that a commit has been made.

Client Hooks

post-checkout runs after you’ve run a successful git checkout command. If you had a set of large files used on the site but didn’t want them in source control, you could use this command to move the files for you.

pre-push runs during a git push command before any objects are transferred to the remote repository.

Server Hooks

pre-receive runs when a client has pushed code to a remote repository. This can be used to check the code that is being pushed to make sure that it meets the criteria of your project before you accept the push.

post-receive runs after your remote repository has received the updates. This could be used to call a web hook which triggers a deployment process or notifying a chat room that a commit has been received and is ready for review.

Many of the hooks above can be set to run only on specific branches. That may mean when you use a post-receive hook only when someone has pushed code to the main branch that’s supposed to be ready to deploy. A list of developers could be notified to review the code and then deploy it. This way you would always have 2 sets of eyes on a deploy which can mean catching mistakes that a single developer can easily miss.

I’ve skipped some of the hooks that are available because I’ve never seen a need to use them. One set of hooks I didn’t talk about is the email workflow hooks. If you’re not accepting patches to your code via email, then you’ll likely never need them. You can find all the available hooks in the documentation.

In practice hooks I’ve used most are:

  • pre-commit
  • pre-push
  • commit-msg
  • pre-receive
  • post-commit
  • post-receive

Now let’s do something with these hooks.

Activating a WordPress Plugin with WP Cli and Git Hooks

For one client project this year I was adding a store, and still doing a few tasks on the main site. That meant the main site did not have any of our WooCommerce plugins installed or activated. I needed to develop the WooCommerce store on one branch and only once I was ready to push it all live, did I want to move WooCommerce over to main.

To start we’ll need a new branch called store. We can get this by using git checkout -b store. This creates a new branch and checks it out for us. Now let’s get the hook ready.

First we need to create the post-checkout hook with this command touch .git/hooks/post-checkout.

Next we need to make it executable. We can do this with the chmod command from terminal chmod +x .git/hooks/post-checkout.

Now open the file in your code editor of choice and copy the code below into your post-checkout file.

#! /bin/bash

wp plugin activate woocommerce

echo "activated WooCommerce"

wp plugin activate automatewoo

echo "activated AutomateWoo"

You can demo this by changing to any branch via terminal. You should see two lines telling you that WooCommerce and AutomateWoo have been activated. We know it’s working, but it’s not quite what we want because it will turn the plugins on every single time we change to any branch.

What we really want is to turn them on when we move to our store branch, and then turn them off when we are on our main branch. To do that we’ll need the hook to detect which branch we are one. Swap the contents of post-checkout with the code below.

#! /bin/bash

oldrev=$1
newrev=$2

branch_name="(git symbolic-ref HEAD 2>/dev/null)"

if [ "refs/head/store" = "$branch_name" ];then
  wp plugin activate woocommerce
 echo "activated Woo"

  wp plugin activate automatewoo
 echo "activated AutomateWoo"
fi

if [ "refs/head/main" = "$branch_name" ];then
 wp plugin deactivate woocommerce
  echo "deactivated Woo"

  wp plugin deactivate automatewoo
  echo "deactivated AutomateWoo"
fi

This code starts by assigning the branch we are checking out to the branch_name variable. Then we have two if statements. The first checks to see if we have moved to the store branch. If we have it uses WP CLI to activate WooCommerce and AutomateWoo.

The next if statement checks to see if we are on the main branch. If we are, it will deactivate the plugins with WP CLI and tell us about it in the terminal.

Controlling Git Workflows with Git Hooks

In a previous post on Git I talked about different Git workflows. One very common use case for hooks is to stop anyone from committing code directly to the main branch. You can use a hook to make sure that all code is merged from a different branch into main.

Start by renaming pre-commit.sample to pre-commit and then make it executable as I’ve described above. Next grab the code below and use it in the pre-commit file.

#! /bin/bash

username=$GIT_AUTHOR_NAME
branch="$(git symbolic-ref HEAD 2>/dev/null)"

if [ "$branch" = "refs/heads/main" ]; then
echo "WHOA that was '"${branch}"' you should not do that. Stop doing silly stuff and create your own branch and merge it."
exit 1 # if you remove this it won't block the commit but it will send the message to slack

fi

This checks to see if we’re on the main branch, and if we are, the commit is stopped. Then it prints a reminder to the user that they shouldn’t be committing directly to the main branch.

Remember many places are changing to main as their branch. Older projects may need master in place here if they haven’t updated.

You could even take this a step further and use cURL to access the API of a chat app and then complain publicly that someone tried to commit to main.

The only limitations of git hooks are your imagination. You could use them to stop someone from committing if a TODO is present in their code or to stop whitespace at the end of a file.

If you have some part of your workflow that is a continual stumbling block, look at hooks to automate it, so that you don’t have to remember.

Source link

Understanding WordPress Unit Testing Jargon

Understanding WordPress Unit Testing Jargon

In our last post, we took a basic look at testing your code in WordPress. Today, we’re going to take another step towards writing well-tested code, by introducing you to (and helping you understand) all the jargon that gets thrown around when you talk about unit testing for WordPress.

Types of Tests

Yup, unit tests are not the only types of tests we can have for our application so let’s look at the different types of tests you may use in your work.

Unit Tests

These types of tests are the first stage in a testing system. They specifically test to ensure that the code you wrote performs as expected. Unit tests form the foundation of your tests because if your code doesn’t work properly, then later types of tests are built on a shaky foundation.

If I wanted to limit the editing of permalinks to site administrators for posts that are over two weeks old my unit test would use WP_Mock to ensure that I have a user of the proper type and a post with the proper date. Then I’d make sure that my function returned the expected true or false value.

Unit tests should have no dependencies outside of the code you’ve written. They should interact with no other system. That means our last post wasn’t a true unit test, it was an integration test because we interacted with the database as we created our user.

When you use unit tests as the foundation of your work, you help ensure that each method/function has a single responsibility because it gets progressively harder to test as you add more conditions to a single function.

Some of the tools you’ll encounter in unit testing WordPress projects are:

Integration Tests

This is the second type of testing you’ll do in your work. Integration tests make sure that the interactions between two systems function as expected. Unlike unit tests, the goal here is to see the interaction between multiple systems.

WordPress itself does more integration tests than unit tests because when most of the application was written best practices were different. The functions inside WordPress are much larger than many newer PHP CMS’s and do much more work. These bigger functions are hard to unit test properly because they do so much. That means we rely more on integration testing as we check how our code directly works with WordPress.

None of this is bad, it’s simply a product of an application that wasn’t built when testing was as common as it is now.

Another example of an integration test would be if you were building an integration with an email marketing platform. You may use unit tests to make sure you validate the email properly, and submit the form as expected. Integration tests would be used to ensure that when you submit your valid email to the email platform you deal with the response properly.

Tools for integration testing:

Mutation Testing

Mutation testing is only going to be used for projects that have some sort of test coverage already. This type of testing creates “mutants” of your code by introducing common coding errors. The goal is that your unit tests break when these errors are introduced which means you’ve caught and killed the mutant. Mutation testing tools will report back on how many mutants you’ve killed and the places in which you haven’t caught mutants.

Mutation testing can be used to measure the quality of your test coverage. If you’ve got lots of mutants alongside 100% testing coverage, you have a big problem. This means that your tests don’t catch common errors programmers make. You’ve got code breakage waiting to happen.

Essentially, you’re testing your tests.

Tools for mutation testing:

Acceptance Tests

These can also be called functional test or browser testing. Where unit tests start with your code and work outwards, acceptance tests take the view of the person using your software. With acceptance tests, you may automate the web browser to interact with your site to make sure that users see what they expect to see.

Acceptance tests are harder to maintain because a small wording change in the UI of your software can mean that the test breaks because the automation can no longer find the UI elements it expects to find. For that reason, only invest in acceptance tests for business-critical infrastructure, like the checkout process on your shopping cart.

Tools for acceptance testing:

Jargon

Now that we’ve covered the types of tests you can do, we need to make sure we understand the other language that developers will use as they write tests.

Test Doubles

The term test doubles is a generic term that refers to any time you replace a production object/function/thing for testing purposes. We did this in our previous post on Getting Started with Unit Testing in WordPress when we used WP_UnitTestCase to add a user that didn’t exist in our production database. It can be helpful to think of it like a stunt double who “stands in” for the actor when things get dangerous. Test doubles “stand-in” for our data and code to make testing easier. They should look and behave like their production counterparts but be simplified to reduce complexity when we’re testing.

Mock

Mocks are used when you don’t want to interact with the API or database. You use a mock to fake database interactions so you can test a single unit of code without adding the complexity of a database.

A mock doesn’t have to be data in a database. A tool like WP_Mock has the ability to fake the hook system inside WordPress. This lets you test to see if a hook was called in your function, without needing to interact with WordPress itself.

Below we can see an example in WP_Mock where we fake the get_permalink function. We provide the number of times we expect the function to be called, arguments we expect, and the value we expect returned.

WPMock::userFunction( 'getpermalink', array(

  'args' => 42,

  'times' => 1,

  'return' => 'https://theanswertoeverything.fourtytwo/guide

We’ll cover how to use WP_Mock in a future post.

Stubs

Stubs are hard coded values for our tests, like canned answers to the questions our test may ask. You would be using a stub if you instructed your test to assume that a user is logged in while running a test. Another test may assume that the user is logged out. Both tests would be making sure that your functions returned the proper values for the given branch in your code.

It’s very likely that you’re using stubs and mocks together. In the example above, you use a stub to assume the logged in value, and then a mock to make sure that the proper values are returned.

Dummies

Test dummies are used when you don’t care about what the code does. Maybe you use a dummy to fill in an array or parameter list so that the code works properly. Stubs are extra information that likely doesn’t matter in the context of the specific test you’re writing.

For a logged-in user, maybe part of the function your testing expects a name. Even if your current test doesn’t need that name, you need to make sure it’s filled in so that your test passes. Of course, you should also test the result of your function without that name so you’re sure that you handle failure conditions properly.

Factories

A factory is a tool that lets us populate valid objects in our data model so that we can test the data. In our last case we used a factory when we added a user to our code inside WP_UnitTestCase.

One thing to be wary of here is changing the data model in your code. If your user suddenly needs an extra field, then you’ll need to head into every test and make sure that you have added that extra field every time you’ve used a factory.

Monkey Patch

This is a catch-all term for dynamically replacing attributes and functions at runtime. WP_Mock is “monkey patching” by replacing the default WordPress functions for testing. This means that we don’t have to call into WordPress directly when we’re unit testing.

Assertions

An assertion is a boolean value which will be true unless there is an error. An example would be using assertFileEquals to check if a file has the expected content. It will return true if the file matches expectations, and you have a passing test.

BDD or TDD?

Now, what overall system are you going to approach your tests with? Does it matter more that individual functions are valid, or that the behavior the end-user sees is valid?

TDD

TDD or Test Driven Development is when you write tests to validate that the code functions as expected. Like unit tests, you’re starting with the expectation of the code and then working towards the customer/user as you go. TDD doesn’t care about the outputs, it’s only concerned that the tests function as expected.

Tests written under TDD are only going to be readable by developers that understand testing and what an assertion means.

BDD

BDD or Behavior Driven Development grew out of the shortcomings of TDD. Here you start with what the end-user expects to happen as a result of the code. You still write your tests first, but you focus them on the result of your code. BDD doesn’t care how you arrive at outputs, as long as the expected behavior is the result.

One big benefit to BDD tools like Cucumber is that the language used to write the test is easily readable by customers and developers. It’s easy enough to understand that customers can write feature requests using Cucumber after a brief introduction.

Now, which one should you use? The correct answer is probably a bit of both. TDD methods can be used to ensure that the code the developer writes runs as expected. BDD can be used to make sure that the output of that code is what the customer expects to happen.

That’s all, folks! Understanding unit testing for WordPress just got a lot easier. With all that jargon under your belt, you’ll be ready for the next post where we’ll build a plugin using TDD and BDD with all the tools at our disposal.

Source link

Introduction to Unit Testing for WordPress

Introduction to Unit Testing for WordPress

While many of us have heard of unit testing, it’s not a big topic of discussion in the WordPress community. Yes, there are tests for WordPress core. Yes, many of the major plugins like WooCommerce have unit tests, but that doesn’t make it easy to jump on the unit testing train. 

While you can find lots of content about unit testing PHP applications, there aren’t many people talking about unit testing specifically for WordPress. There is precious little written about where to start for developers that are ready to increase their code quality and want to learn how to add tests to their work. Even worse, some of the tools for unit testing in WordPress don’t work as advertised, or are using older versions of PHPUnit. Problems you’ll have to discover on your own as you try to start testing.

That leaves many people who want to get started with testing on a multi-hour journey to get even the basic default tests running for their plugin.

Today we’re going to solve that problem by giving you an up-to-date look at how to start unit testing your WordPress code.

Things to Have Installed

Before we dive into unit testing, I’m going to assume you have Laravel Valet and WP CLI installed. I use these excellent directions from WP Beaches to install Valet, though I use the mysql instructions not the MariaDB ones. 

You can find the instructions to install WP CLI on the WP CLI site.

If you’re on Windows, you may have a bit of extra digging to do so you can run unit tests. The WordPress Handbook has some instructions on the extra steps you’ll need to take.

Install PHPUnit for WordPress on Laravel Valet

Our first step is to install PHPUnit. While PHPUnit is currently on the 9.x branch, WordPress only supports 7.5.x which means we’ll need to install this older version.

Open up the terminal and use these commands.

wget https://phar.phpunit.de/phpunit-7.5.9.phar

chmod +x phpunit-7.5.9.phar`

sudo mv phpunit-7.5.9.phar /usr/local/bin/phpunit

phpunit --version

The command above, download PHPUnit. Then we make the file executable so it can be run. Next, we use the sudo command to move the file to the proper location on our computer. Finally, we check for the version number, which should return 7.5.9 when we run the final command.

Now we’re ready to set up our plugin with WP CLI and take a look at our first tests.

Setting Up Our Plugin

We can make starting a plugin, and getting our unit test scaffold, easy with the WP CLI scaffold command. This command will create a plugin for us, and add all the files we need to have a foundation for our tests.

In the terminal, make sure you’re in the proper WordPress directory you want to use and then type wp scaffold nexcess-unit-tests. That should give you a folder structure that looks like this.

– bin

    – install-wp-tests.sh

– tests

    – bootstrap.php

    – test-sample.php

– .distignore

– .editorconfig

– .phpcs.xml.dist

– .travis.yml

– Gruntfile.js

– nexcess-unit-tests.php

– package.json

– phpunit.xml.dist

– readme.txt

If you want to build out the basics of a plugin but not include tests then you’d use the –skip-tests flag, which will skip the generation of test files. You can see all the options available for this command in the WP CLI documentation.

Depending on how your code editor and file system are set, you may not see the files that begin with a . because they’re considered hidden files. For our purposes today, they don’t matter so don’t worry about it if you don’t see them.

Now we need to hook our unit tests up to MySQL so that it can create dummy data for us to test against. Open up the wp-config.php file for your WordPress installation now because you’re going to need to find the db_user and db_pass for the next command.

To finish installing the tests change to your plugin directory and run the following command.

bin/install-wp-tests.sh <db-name> <db-user> <db-pass> localhost latest

Make sure you use a different db-name than your WordPress install. You don’t want your unit tests messing with your data, you want it creating its own test data in its own database. Otherwise, the db-user and db-pass will be the same as your wp-config.php file.

The final two parameters tell the testing framework to connect to localhost and to install the latest version of WordPress to test with. Unless you know better, just leave those settings as they are.

If we were to run phpunit now, we’d still have a few errors to resolve. First, for some reason WP CLI doesn’t add the name attribute to the <testsuite> block in the sample tests. Open phpunit.xml.dist and change <testsuite> to <testsuite name=”Unit Tests”> and save the file.

Also note here that inside the <testsuite> block PHPUnit is told to ignore the tests/test-sample.php file. Let’s duplicate that file and rename it to test-nexcess.php so that we have a file which will run. Then open the new file and change the class name to NexcessTest. The file should look like this now.

<?php

/**

 * Class NexcessTest

 *

 * @package Nexcess_Unit_Tests

 */

/**

 * Sample test case.

 */

class NexcessTest extends WP_UnitTestCase {

    /**

     * A single example test.

     */

    public function test_sample() {

        // Replace this with some actual testing code.

        $this->assertTrue( true );

    }

}

Now we’re ready to run phpunit from the terminal. Once you’ve done that you should see something like the image below.

Now that we’ve confirmed that PHPUnit is running our tests, let’s dive a little deeper and write a test to make sure that WordPress is adding users properly.

setUp and tearDown

Most unit tests will require specific data to be added to the testing database. Then you run your tests against this fake data. To do this you use the setUp and tearDown functions in your testing class.

Let’s create a user and then make sure that the user has the edit_posts capability. Add the following function to the top of your class.

   public function setUp(){

        // make a fake user

        $this->author = new WP_User( $this->factory->user->create( array( 'role' => 'editor' ) ) );

    }

Then add this tearDown function to the end of the class.

public function tearDown(){

        parent::tearDown();

        wp_delete_user($this->author->ID, true);

}

This adds a user with the role of editor before we run our tests, and then removes the user after we’ve run our tests.

Now let’s write a simple test to verify that the user was added properly and has the proper capabilities.

   public function testUser(){

        // make sure setUp user has the cap we want

        $user = get_user_by( 'id', $this->author->ID );

        $this->assertTrue( user_can( $user, 'edit_posts' ), 'The user does not have the edit_posts capability and they should not' );

        $this->assertFalse( user_can( $user, 'activate_plugins' ), 'The user can activate plugins and the should not be able to' );

    }

Above we start by getting the user object based on the fake user we created. We’ll need this object to test our capabilities which we do next with the assertTrue and assertFalse statements.

In this instance assertTrue is expecting that our user_can( $user, ‘edit_posts’ ) returns true. We’re testing to make sure that the user object provided is given the edit_posts capability, as an editor should have. If this were to return false, we’d see the message provided in our unit test output in the terminal.

Next, we test to make sure that the same user doesn’t have capabilities of an admin user. Here we use assertFalse while checking for the activate_plugins capability. This should return false because activate_plugins` is for the Admin role in WordPress not for Editors.

Once you have that code added after your setUp function, head to terminal and run phpunit. You should see 2 tests are okay, with 3 assertions.

PHPUnit considers our testUser function to be a test, and the assertTrue/assertFalse statements inside to be assertions.

What does that factory thing mean?

Before we finish here, let me draw your attention back to our setUp function. Specifically the factory section when we create a new user. 

When you use the WP CLI scaffold, it gives you access to the WP_UnitTest_Factory class. This class is there as a helper to create the data you’ll need to run your tests properly. You can use this factory to create posts, attachments, comments, users, terms, and some other things for WordPress Multisite.

This is not the only tool you can use to mimic WordPress for your tests though. In a future post we’ll look at WP_Mock to test parts of WordPress that the built-in factory doesn’t reach very well.

Today, we covered a fair bit of complex ground as we looked at unit testing your WordPress projects. I know when I started unit testing it looked daunting, but it’s worth it if you want code that works, and lets you know when you’ve broken something, so your customers don’t have to find the problem for you. Over the long-term, you’ll save time and headaches by writing testable code and aiming for decent test coverage in your projects.

Further Resources

Source link