Skip to content

Commit

Permalink
Switch all tests to nose2 (#127)
Browse files Browse the repository at this point in the history
- Convert all test files to be nose2-compatible.
- Add nose2 configuration file.
- Update Gitlab CI file.
  - Use Python 3.11 instead of Python 3.9.
  - Use nose2 for testing instead of nose.
- Update README.rst.
  - Add PyPI badge.
  - Fix conda badge.
  • Loading branch information
desilinguist authored Jul 7, 2023
1 parent 7ed3a97 commit 8876085
Show file tree
Hide file tree
Showing 8 changed files with 893 additions and 1,018 deletions.
12 changes: 5 additions & 7 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ stages:
- test

variables:
PYVERSION: "3.9"
NOSE_WITH_COV: "1"
NOSE_COVER_PACKAGE: "factor_analyzer"
PYVERSION: "3.11"
LOGCAPTURE_LEVEL: "DEBUG"
CODECOV_TOKEN: "034f0bb1-e590-406f-820c-4e7c41b17712"

# set up the basic job
.runtests:
before_script:
- "conda create --prefix /root/factordev --channel conda-forge --file requirements.txt python=${PYVERSION} curl nose nose-cov --yes --quiet"
- "conda create --prefix /root/factordev --channel conda-forge --file requirements.txt python=${PYVERSION} curl nose2 coverage --yes --quiet"
- /root/factordev/bin/pip install -e .
- /root/factordev/bin/curl -o /root/factordev/bin/codecov https://uploader.codecov.io/latest/linux/codecov
- chmod +x /root/factordev/bin/codecov
script:
- "/root/factordev/bin/nosetests ${TESTFILES}"
- "/root/factordev/bin/nose2 -s tests ${TESTFILES}"
- "/root/factordev/bin/coverage xml"
after_script:
- /root/factordev/bin/codecov
Expand All @@ -27,12 +25,12 @@ variables:
testset1:
extends: ".runtests"
variables:
TESTFILES: "tests/test_expected_confirmatory_factor_analyzer.py tests/test_factor_analyzer.py"
TESTFILES: "test_expected_confirmatory_factor_analyzer test_factor_analyzer"
stage: "test"

# second set of test files
testset2:
extends: ".runtests"
variables:
TESTFILES: "tests/test_expected_factor_analyzer.py tests/test_expected_rotator.py tests/test_utils.py"
TESTFILES: "test_expected_factor_analyzer test_expected_rotator test_utils"
stage: "test"
6 changes: 5 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ FactorAnalyzer
:target: https://codecov.io/gh/EducationalTestingService/factor_analyzer
:alt: Code coverage

.. image:: https://anaconda.org/ets/factor_analyzer/badges/installer/conda.svg
.. image:: https://anaconda.org/ets/factor_analyzer/badges/version.svg
:target: https://anaconda.org/ets/factor_analyzer/
:alt: Conda version

.. image:: https://img.shields.io/pypi/v/factor_analyzer
:target: https://pypi.org/project/factor-analyzer/
:alt: PyPI version

.. image:: https://img.shields.io/readthedocs/factor_analyzer/latest.svg
:target: https://factor-analyzer.readthedocs.io/
:alt: Docs
Expand Down
143 changes: 68 additions & 75 deletions tests/test_expected_confirmatory_factor_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
:organization: Educational Testing Service
:date: 2022-09-05
"""
import unittest

import numpy as np
import pandas as pd
from nose.tools import eq_, raises
from numpy.testing import assert_array_equal

from factor_analyzer.confirmatory_factor_analyzer import (
Expand All @@ -21,81 +22,69 @@
THRESHOLD = 1.0


def test_11_cfa(): # noqa: D103

json_name_input = "test11"
data_name_input = "test11"

for check in check_cfa(json_name_input, data_name_input, rel_tol=0.1):
assert check >= THRESHOLD


def test_12_cfa(): # noqa: D103

json_name_input = "test12"
data_name_input = "test12"

for check in check_cfa(json_name_input, data_name_input, abs_tol=0.05):
assert check >= THRESHOLD

class TestConfirmatoryFactorAnalysis(unittest.TestCase):
def test_11_cfa(self): # noqa: D103
json_name_input = "test11"
data_name_input = "test11"

def test_13_cfa(): # noqa: D103
for check in check_cfa(json_name_input, data_name_input, rel_tol=0.1):
self.assertGreaterEqual(check, THRESHOLD)

json_name_input = "test13"
data_name_input = "test13"
def test_12_cfa(self): # noqa: D103
json_name_input = "test12"
data_name_input = "test12"

for check in check_cfa(
json_name_input,
data_name_input,
index_col=0,
is_cov=True,
n_obs=64,
rel_tol=0.1,
):
assert check >= THRESHOLD
for check in check_cfa(json_name_input, data_name_input, abs_tol=0.05):
self.assertGreaterEqual(check, THRESHOLD)

def test_13_cfa(self): # noqa: D103
json_name_input = "test13"
data_name_input = "test13"

def test_14_cfa(): # noqa: D103
for check in check_cfa(
json_name_input,
data_name_input,
index_col=0,
is_cov=True,
n_obs=64,
rel_tol=0.1,
):
self.assertGreaterEqual(check, THRESHOLD)

json_name_input = "test14"
data_name_input = "test14"
def test_14_cfa(self): # noqa: D103
json_name_input = "test14"
data_name_input = "test14"

for check in check_cfa(json_name_input, data_name_input, index_col=0, rel_tol=0.1):
assert check >= THRESHOLD
for check in check_cfa(
json_name_input, data_name_input, index_col=0, rel_tol=0.1
):
self.assertGreaterEqual(check, THRESHOLD)

def test_14_cfa_no_model(self): # noqa: D103
X = np.array([[0, 0, 0, 0], [0, 0, 0, 0]])

@raises(ValueError)
def test_14_cfa_no_model(): # noqa: D103
with self.assertRaises(ValueError):
cfa = ConfirmatoryFactorAnalyzer("string_not_model")
cfa.fit(X)

X = np.array([[0, 0, 0, 0], [0, 0, 0, 0]])
def test_14_cfa_bad_bounds(self): # noqa: D103
X = np.array([[0, 0, 0, 0], [0, 0, 0, 0]])

cfa = ConfirmatoryFactorAnalyzer("string_not_model")
cfa.fit(X)
with self.assertRaises(AssertionError):
cfa = ConfirmatoryFactorAnalyzer(bounds=[(0, 1)])
cfa.fit(X)

def test_14_cfa_cov_with_no_obs(self): # noqa: D103
with self.assertRaises(ValueError):
ConfirmatoryFactorAnalyzer(is_cov_matrix=True)

@raises(AssertionError)
def test_14_cfa_bad_bounds(): # noqa: D103

X = np.array([[0, 0, 0, 0], [0, 0, 0, 0]])

cfa = ConfirmatoryFactorAnalyzer(bounds=[(0, 1)])
cfa.fit(X)


@raises(ValueError)
def test_14_cfa_cov_with_no_obs(): # noqa: D103

ConfirmatoryFactorAnalyzer(is_cov_matrix=True)


class TestModelSpecificationParser: # noqa: D101
class TestModelSpecificationParser(unittest.TestCase):
def test_model_spec_str(self): # noqa: D102

ms = ModelSpecification(np.array([[0, 0, 0]]), 3, 1)
assert str(ms).startswith("<ModelSpecification object at ")
self.assertTrue(str(ms).startswith("<ModelSpecification object at "))

def test_model_spec_as_dict(self): # noqa: D102

loadings = np.array([[0, 0, 0]])
n_factors = 3
n_variables = 1
Expand All @@ -112,48 +101,52 @@ def test_model_spec_as_dict(self): # noqa: D102
if isinstance(value, np.ndarray):
assert_array_equal(new_dict[key], value)
else:
eq_(new_dict[key], value)
self.assertEqual(new_dict[key], value)

def test_model_spec_parser_from_dict_none(self): # noqa: D102
X = np.array([[0, 0, 0]])
ms = ModelSpecificationParser.parse_model_specification_from_dict(X, None)
assert isinstance(ms, ModelSpecification)
eq_(ms.n_factors, 3)
eq_(ms.n_variables, 3)
self.assertTrue(isinstance(ms, ModelSpecification))
self.assertEqual(ms.n_factors, 3)
self.assertEqual(ms.n_variables, 3)
assert_array_equal(ms.loadings, np.ones((3, 3), dtype=int))

@raises(ValueError)
def test_model_spec_parser_from_dict_error(self): # noqa: D102
X = np.array([[0, 0, 0]])
ModelSpecificationParser.parse_model_specification_from_dict(X, "not_a_model")
with self.assertRaises(ValueError):
ModelSpecificationParser.parse_model_specification_from_dict(
X, "not_a_model"
)

def test_model_spec_parser_from_array_none(self): # noqa: D102
X = np.array([[0, 0, 0]])
ms = ModelSpecificationParser.parse_model_specification_from_array(X, None)
assert isinstance(ms, ModelSpecification)
eq_(ms.n_factors, 3)
eq_(ms.n_variables, 3)
self.assertTrue(isinstance(ms, ModelSpecification))
self.assertEqual(ms.n_factors, 3)
self.assertEqual(ms.n_variables, 3)
assert_array_equal(ms.loadings, np.ones((3, 3), dtype=int))

def test_model_spec_parser_from_array(self): # noqa: D102
X = np.array([[0, 0, 0]])
spec = np.ones((3, 3), dtype=int)
ms = ModelSpecificationParser.parse_model_specification_from_array(X, spec)
assert isinstance(ms, ModelSpecification)
eq_(ms.n_factors, 3)
eq_(ms.n_variables, 3)
self.assertTrue(isinstance(ms, ModelSpecification))
self.assertEqual(ms.n_factors, 3)
self.assertEqual(ms.n_variables, 3)
assert_array_equal(ms.loadings, np.ones((3, 3), dtype=int))

def test_model_spec_parser_from_frame(self): # noqa: D102
X = np.array([[0, 0, 0]])
spec = pd.DataFrame(np.ones((3, 3), dtype=int))
ms = ModelSpecificationParser.parse_model_specification_from_array(X, spec)
assert isinstance(ms, ModelSpecification)
eq_(ms.n_factors, 3)
eq_(ms.n_variables, 3)
self.assertTrue(isinstance(ms, ModelSpecification))
self.assertEqual(ms.n_factors, 3)
self.assertEqual(ms.n_variables, 3)
assert_array_equal(ms.loadings, np.ones((3, 3), dtype=int))

@raises(ValueError)
def test_model_spec_parser_from_array_error(self): # noqa: D102
X = np.array([[0, 0, 0]])
ModelSpecificationParser.parse_model_specification_from_array(X, "not_a_model")
with self.assertRaises(ValueError):
ModelSpecificationParser.parse_model_specification_from_array(
X, "not_a_model"
)
Loading

0 comments on commit 8876085

Please sign in to comment.