Skip to content

Commit

Permalink
Merge pull request #50 from chris-greening/add-automated-unit-testing
Browse files Browse the repository at this point in the history
Add automated unit testing
  • Loading branch information
chris-greening authored Mar 18, 2023
2 parents f04dccd + 33d57d6 commit 7505da4
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pylint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
pip install numpy
- name: Analysing the code with pylint
run: |
pylint $(git ls-files '*.py')
pylint $(git ls-files 'spyrograph/*.py')
23 changes: 23 additions & 0 deletions .github/workflows/pytest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Pytest

on: [pull_request]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pandas numpy
- name: Unit testing the code with pytest
run: |
pytest tests
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ ignore-paths=
# Files or directories matching the regular expression patterns are skipped.
# The regex matches against base names, not paths. The default value ignores
# Emacs file locks
ignore-patterns=^\.#
ignore-patterns=^\.#,tests

# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
Expand Down
Empty file added tests/__init__.py
Empty file.
123 changes: 123 additions & 0 deletions tests/_roulette.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import pytest

import numpy as np
import pandas as pd

class _TestGeneral:
# Define this class attr in subclasses
class_name = None
@pytest.fixture()
def thetas(self) -> "np.array":
"""Return a numpy array of theta values"""
return np.arange(0, np.pi*2, .1)

@pytest.fixture()
def instance(self, thetas):
"""Return an instance of the shape"""
return self.class_name(
R = 300,
r = 200,
d = 100,
thetas=thetas
)

def test_theta_range(self) -> None:
"""Test that passing theta start, stop, step creates an expected list of theta values"""
obj = self.class_name(
R = 300,
r = 200,
d = 100,
theta_start=1,
theta_stop=10,
theta_step=1
)
assert all(obj.thetas == np.arange(1,10,1))

def test_theta_range_default_step(self) -> None:
"""Test that passing theta start, stop, step creates an expected list of theta values"""
obj = self.class_name(
R = 300,
r = 200,
d = 100,
theta_start=0,
theta_stop=1
)

def test_multiple_thetas_exception(self, thetas: "np.array") -> None:
"""Test that passing multiple definitions of setting theta raises a ValueError"""
with pytest.raises(ValueError):
obj = self.class_name(
R = 300,
r = 200,
d = 100,
thetas=thetas,
theta_start=1,
theta_stop=10,
theta_step=1
)

def test_coords(self, instance) -> None:
"""Test that coordinates attribute matches x, y, and theta values"""
assert instance.coords[0] == (instance.x[0], instance.y[0], instance.thetas[0])
assert instance.coords[-1] == (instance.x[-1], instance.y[-1], instance.thetas[-1])

def test_dataframe_property(self, instance) -> None:
"""Test that DataFrame property is working as expected"""
assert isinstance(instance.df, pd.DataFrame)
assert list(instance.df.columns) == ["x", "y", "theta"]
assert all(instance.df["x"].to_numpy() == instance.x)
assert all(instance.df["y"].to_numpy() == instance.y)
assert all(instance.df["theta"].to_numpy() == instance.thetas)

class _TestSpecial:
# Define this class attr in subclasses
class_name = None
@pytest.fixture()
def thetas(self) -> "np.array":
"""Return a numpy array of theta values"""
return np.arange(0, np.pi*2, .1)

@pytest.fixture()
def instance(self, thetas):
"""Return an instance of the shape"""
return self.class_name(
R = 300,
r = 200,
thetas=thetas
)

def test_theta_range(self) -> None:
"""Test that passing theta start, stop, step creates an expected list of theta values"""
obj = self.class_name(
R = 300,
r = 200,
theta_start=1,
theta_stop=10,
theta_step=1
)
assert all(obj.thetas == np.arange(1,10,1))

def test_theta_range_default_step(self) -> None:
"""Test that passing theta start, stop, step creates an expected list of theta values"""
obj = self.class_name(
R = 300,
r = 200,
theta_start=0,
theta_stop=1
)

def test_multiple_thetas_exception(self, thetas: "np.array") -> None:
"""Test that passing multiple definitions of setting theta raises a ValueError"""
with pytest.raises(ValueError):
obj = self.class_name(
R = 300,
r = 200,
thetas=thetas,
theta_start=1,
theta_stop=10,
theta_step=1
)

def test_rolling_radius_equals_distance(self, instance):
"""Test radius of rolling circle is equal to distance"""
assert instance.r == instance.d
14 changes: 14 additions & 0 deletions tests/test_epitrochoid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import pytest

from tests._roulette import _TestGeneral, _TestSpecial
from spyrograph.epitrochoid.epitrochoid import Epitrochoid
from spyrograph.epitrochoid.epicycloid import Epicycloid

class TestEpitrochoid(_TestGeneral):
class_name = Epitrochoid

def test_circle_offset(self, instance):
assert instance._circle_offset() == 500

class TestEpicycloid(_TestSpecial, TestEpitrochoid):
class_name = Epicycloid
15 changes: 15 additions & 0 deletions tests/test_hypotrochoid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import numpy as np
import pytest

from tests._roulette import _TestGeneral, _TestSpecial
from spyrograph.hypotrochoid.hypotrochoid import Hypotrochoid
from spyrograph.hypotrochoid.hypocycloid import Hypocycloid

class TestHypotrochoid(_TestGeneral):
class_name = Hypotrochoid

def test_circle_offset(self, instance):
assert instance._circle_offset() == 100

class TestHypocycloid(_TestSpecial, TestHypotrochoid):
class_name = Hypocycloid

0 comments on commit 7505da4

Please sign in to comment.