From cbda8e7cc339359b45898a4aea033a41901b768c Mon Sep 17 00:00:00 2001 From: Lukasz Mentel Date: Sun, 29 Dec 2024 15:16:41 +0100 Subject: [PATCH] [MNT] Increase test coverage (#216) * refactor fixtures * update tests * add test for electronegativity functions * :lipstick: * add pytest-cov --- mendeleev/models.py | 12 ++-- poetry.lock | 107 +++++++++++++++++++++++++++++++- pyproject.toml | 2 + tests/test_electronegativity.py | 61 +++++++++++++++++- tests/test_element.py | 70 ++++++++++++++++----- 5 files changed, 228 insertions(+), 24 deletions(-) diff --git a/mendeleev/models.py b/mendeleev/models.py index 595e576..d28d67c 100644 --- a/mendeleev/models.py +++ b/mendeleev/models.py @@ -377,7 +377,7 @@ def protons(self) -> int: @hybrid_property def mass(self) -> float: """ - Return the `atomic_weight` if defined or mass number otherwise. + Alias for ``atomic_weight``. """ return self.atomic_weight @@ -414,7 +414,7 @@ def mass_str(self) -> str: @hybrid_property def covalent_radius(self) -> float: """ - Return the default covalent radius which is covalent_radius_pyykko + Return the default covalent radius i.e. ``covalent_radius_pyykko`` """ return self.covalent_radius_pyykko @@ -424,8 +424,8 @@ def hardness(self, charge: int = 0) -> Union[float, None]: Return the absolute hardness, calculated as Args: - charge: Charge of the cation for which the hardness will be calculated. - Defaultf to 0. + charge: Charge of the cation for which the hardness will be calculated. + Default is 0. .. math:: @@ -457,12 +457,12 @@ def hardness(self, charge: int = 0) -> Union[float, None]: raise ValueError(f"Charge has to be a non-negative integer, got: {charge}") @hybrid_method - def softness(self, charge: int = 0) -> Union[float, None]: + def softness(self, charge: int = 0) -> float | None: r""" Return the absolute softness. Args: - charge: Charge of the cation for which the hardness will be calculated + charge: Charge of the cation for which the hardness will be calculated .. math:: diff --git a/poetry.lock b/poetry.lock index 9bfe198..5f89e56 100644 --- a/poetry.lock +++ b/poetry.lock @@ -728,6 +728,88 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "coverage" +version = "7.6.10" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"}, + {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"}, + {file = "coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a"}, + {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165"}, + {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988"}, + {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5"}, + {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3"}, + {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5"}, + {file = "coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244"}, + {file = "coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e"}, + {file = "coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3"}, + {file = "coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43"}, + {file = "coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132"}, + {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f"}, + {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994"}, + {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99"}, + {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd"}, + {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377"}, + {file = "coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8"}, + {file = "coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609"}, + {file = "coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853"}, + {file = "coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078"}, + {file = "coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0"}, + {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50"}, + {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022"}, + {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b"}, + {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0"}, + {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852"}, + {file = "coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359"}, + {file = "coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247"}, + {file = "coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9"}, + {file = "coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b"}, + {file = "coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690"}, + {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18"}, + {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c"}, + {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd"}, + {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e"}, + {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694"}, + {file = "coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6"}, + {file = "coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e"}, + {file = "coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe"}, + {file = "coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273"}, + {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8"}, + {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098"}, + {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb"}, + {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0"}, + {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf"}, + {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2"}, + {file = "coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312"}, + {file = "coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d"}, + {file = "coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a"}, + {file = "coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27"}, + {file = "coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4"}, + {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f"}, + {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25"}, + {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315"}, + {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90"}, + {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d"}, + {file = "coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18"}, + {file = "coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59"}, + {file = "coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"}, + {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "css-html-js-minify" version = "2.5.5" @@ -3505,6 +3587,29 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "pytest-cov" +version = "6.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +files = [ + {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, + {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, +] + +[package.dependencies] +coverage = {version = ">=7.5", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "pytest-xdist" version = "3.6.1" @@ -5208,4 +5313,4 @@ reference = "pypi-public" [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.14" -content-hash = "4e8f42c26cd9536ac505f540bc79fb4c79967b029fd45415491b2d9894ea9ae0" +content-hash = "d24863bb405a7e00763b5456345134c48498a98d690f4e480c7db371d9354079" diff --git a/pyproject.toml b/pyproject.toml index ddae40f..81c168d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -70,6 +70,8 @@ sphinx-copybutton = "^0.3.1" sphinx-material = "^0.0.32" sphinxcontrib-bibtex = "^2.1.4" pytest-xdist = "^3.6.1" +coverage = "^7.6.10" +pytest-cov = "^6.0.0" [tool.poetry.group.vis] optional = true diff --git a/tests/test_electronegativity.py b/tests/test_electronegativity.py index 483c733..e821873 100644 --- a/tests/test_electronegativity.py +++ b/tests/test_electronegativity.py @@ -1,7 +1,18 @@ import pytest from mendeleev.models import Element -from mendeleev.electronegativity import mulliken +from mendeleev.electronegativity import ( + n_effective, + allred_rochow, + cottrell_sutton, + gordy, + li_xue, + martynov_batsanov, + mulliken, + nagle, + sanderson, + generic, +) def test_scales_exception(): @@ -15,3 +26,51 @@ def test_mulliken(): assert mulliken(None, 1.0) is None assert mulliken(2.0, None) == pytest.approx(1.0) assert mulliken(2.0, 1.0) == pytest.approx(1.5) + + +def test_n_effective(): + assert n_effective(1, "slater") == pytest.approx(1.0) + assert n_effective(3, "zhang") == pytest.approx(2.89) + with pytest.raises(ValueError): + n_effective(2, "invalid") + + +def test_allred_rochow(): + assert allred_rochow(4.0, 1.0) == pytest.approx(4.0) + assert allred_rochow(9.0, 3.0) == pytest.approx(1.0) + + +def test_cottrell_sutton(): + assert cottrell_sutton(4.0, 1.0) == pytest.approx(2.0) + assert cottrell_sutton(9.0, 4.0) == pytest.approx(1.5) + + +def test_gordy(): + assert gordy(6.0, 2.0) == pytest.approx(3.0) + assert gordy(8.0, 4.0) == pytest.approx(2.0) + + +def test_li_xue(): + assert li_xue(13.6, 1.0, 1) == pytest.approx( + n_effective(1, "zhang") * 100.0, rel=1e-1 + ) + + +def test_martynov_batsanov(): + assert martynov_batsanov([13.6, 24.6]) == pytest.approx(4.370354676682432) + assert martynov_batsanov([10.0, 20.0, 30.0]) == pytest.approx(4.47213595499958) + + +def test_nagle(): + assert nagle(2, 4.0) == pytest.approx(0.7937005259840998) + assert nagle(8, 64.0) == pytest.approx(0.5) + + +def test_sanderson(): + assert sanderson(1.0, 2.0) == pytest.approx(8.0) + assert sanderson(2.0, 4.0) == pytest.approx(8.0) + + +def test_generic(): + assert generic(4.0, 2.0, 2, 1) == pytest.approx(1.0) + assert generic(9.0, 3.0, 2, 0.5) == pytest.approx(1.0) diff --git a/tests/test_element.py b/tests/test_element.py index d56ef99..da081e5 100644 --- a/tests/test_element.py +++ b/tests/test_element.py @@ -1,3 +1,4 @@ +import math import pytest from mendeleev import element, get_all_elements, get_attribute_for_all_elements from mendeleev.db import get_session @@ -47,30 +48,46 @@ def test_elements_get_by_name(name): assert e.name == name -@pytest.mark.parametrize("symbol", SYMBOLS) -def test_elements_str(symbol): - e = element(symbol) - str(e) +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_elements_str(element_obj): + str(element_obj) -@pytest.mark.parametrize("symbol", SYMBOLS) -def test_elements_repr(symbol): - e = element(symbol) - repr(e) +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_elements_repr(element_obj): + repr(element_obj) -@pytest.mark.parametrize("symbol", SYMBOLS) -def test_isotopes_str(symbol): - e = element(symbol) - for i in e.isotopes: +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_isotopes_str(element_obj): + for i in element_obj.isotopes: str(i) repr(i) -@pytest.mark.parametrize("symbol", SYMBOLS) -def test_electrophilicity(symbol): - e = element(symbol) - e.electrophilicity() +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_electrophilicity(element_obj): + assert isinstance(element_obj.electrophilicity(), (float, type(None))) + + +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_hardness(element_obj): + assert isinstance(element_obj.hardness(), (float, type(None))) + + +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_hardness_charge_1(element_obj): + assert isinstance(element_obj.hardness(charge=1), (float, type(None))) + + +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_softness(element_obj): + assert isinstance(element_obj.softness(), (float, type(None))) + + +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_softness_charge_1(element_obj): + assert isinstance(element_obj.softness(charge=1), (float, type(None))) @pytest.mark.parametrize("element_obj", ELEMENTS) @@ -92,3 +109,24 @@ def test_melting_points_float_or_none(e): @pytest.mark.parametrize("e", ELEMENTS) def test_boiling_points_float_or_none(e): assert isinstance(e.boiling_point, (float, type(None))) + + +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_specific_heat_hybrid_property(element_obj): + if ( + element_obj.specific_heat is not None + and element_obj.specific_heat_capacity is not None + ): + assert math.isclose( + element_obj.specific_heat, element_obj.specific_heat_capacity, rel_tol=1e-5 + ) + + +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_protons(element_obj): + assert element_obj.protons == element_obj.atomic_number + + +@pytest.mark.parametrize("element_obj", ELEMENTS) +def test_electrons(element_obj): + assert element_obj.electrons == element_obj.atomic_number