Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write unit tests for GitPython clone/pull functions?

I have a python project that is using GitPython to perform clone and pull functions against a remote Git repository.

As a simple example:

import git
from git import Git
from git import Repo


def clone_and_checkout(full_dir, git_url, repo_ver):

    repo = Repo.clone_from(
        url=git_url,
        to_path=full_dir
    )

    # Trigger re-create if repository is bare
    if repo.bare:
        raise git.exc.InvalidGitRepositoryError

    # Set origin and pull
    origin = repo.remotes.origin
    origin.pull()

    # Check out desired version of repository
    g = Git(full_dir)
    g.checkout(repo_ver)

I want to be able to write a unit test for this function, but obviously this needs to reach out to an external system as it stands currently.

I am curious if anyone has experience mocking up this external interaction, in a manner similar to using Mock to mock up HTTP calls. I'd like to be able to perform these tasks in a way that can be mocked at test time without needing to call an actual Git remote.

How should I go about writing tests for this?

EDIT: To be clearer about what I'm asking, I should mention I'm new to Mock and was struggling to understand how to Mock instances of these classes rather than the classes themselves. My question should have been phrased better - something along the lines of "how do I use Mock to set instance-specific properties like bare?"

I have since learned much about Mock and have figured out how to do this, so I will provide an answer to my own question.

like image 244
Mierdin Avatar asked Sep 26 '22 20:09

Mierdin


1 Answers

This seems to be a common result of an incomplete understanding of Mock, or the use of the Patch method.

The first thing to do is read the "where to patch" section located on the Mock documentation. Armed with that information, you should be able to use the patch function to mock the GitPython objects used in the function above. These decorators would appear above your unit test function.

@mock.patch('gitter.Repo')
@mock.patch('gitter.Git')

In order to provide a return value for an instance of one of these mocked objects, you can use PropertyMock. Here's a full example of a unit test which leverages this:

import gitter  # file containing our clone function
import mock
import unittest


class test_gitter(unittest.TestCase):

    @mock.patch('gitter.Repo')
    @mock.patch('gitter.Git')
    def runTest(self, mock_git, mock_repo):

        # Set the "bare" attribute of the Repo instance to be False
        p = mock.PropertyMock(return_value=False)
        type(mock_repo.clone_from.return_value).bare = p

        gitter.clone_and_checkout(
            '/tmp/docker',
            '[email protected]:docker/docker.git',
            'master'
        )
        mock_git.checkout.called_once_with('master')
like image 188
Mierdin Avatar answered Oct 09 '22 10:10

Mierdin