Skip to content

Commit

Permalink
Improve readability of assersions (#25)
Browse files Browse the repository at this point in the history
* Improve readability of Assertions
- Make Assertions return bool or AssertionError
- Change examples of built-in Assertions to ues `it.IAssertion`

* Fix REDAME

* Fix example in README
  • Loading branch information
douglasdcm authored Jan 13, 2025
1 parent a21087b commit d1e24f1
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 38 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ def test_sample_web_page():

# Still at Home page changes the language
# to English and uses native assertion to validate the `result`
assert app.at(home.ChangeToEnglish).result == content_in_english

result = app.at(home.ChangeToEnglish).result
assert it.IsEqualto().asserts(result, content_in_english)

# At Info page asserts the text is present
app.at(info.NavigateTo).asserts(
it.Contains, "This project was born"
Expand Down
4 changes: 3 additions & 1 deletion docs/TUTORIAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ class IsEqualToVariationsOf(IAssertion):
super().__init__()

def asserts(self, actual, expected):
assert actual.lower() == expected.lower()
if actual.lower() == expected.lower():
return True
raises AssertionError

def test_google_search(setup_app):
app = setup_app
Expand Down
7 changes: 4 additions & 3 deletions examples/unit_test/todo_list/test_todo.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def test_remove_task(self):
self._todo.at(operations.Remove, task=task).asserts(it.IsEqualTo, expected)

def test_list_tasks(self):
task = []
task = "any task"
expected = [task]
self._todo.at(operations.Add, task=task)
self._todo.at(operations.ListTasks).asserts(it.IsEqualTo, expected)
Expand All @@ -33,10 +33,11 @@ def test_list_tasks_many_assertions(self):
self._todo.at(operations.Add, task=task)
self._todo.at(operations.Add, task=task_2)
self._todo.at(operations.Add, task=task_3)
self._todo.at(operations.ListTasks).asserts(it.IsSortedAs, expected)

sub_set = [task, task_3]
self._todo.at(operations.ListTasks).asserts(it.HasSubset, sub_set)
result = self._todo.at(operations.ListTasks).result
assert it.HasSubset().validates(result, sub_set)
assert it.IsSortedAs().validates(result, expected)

key_value = {"1": task}
self._todo.at(operations.PrintDict).asserts(it.HasKeyValue, key_value)
Expand Down
6 changes: 3 additions & 3 deletions examples/web_ui/caqui_async/synchronous/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ def _run_it(self):
for i in range(max_index):

# act
actual = self._app.at(
result = self._app.at(
home.GetNthLink,
link_index=i + 1,
)
).result

# assert
assert actual.result == f"any{i+1}.com"
assert it.IsEqualTo().asserts(result, f"any{i+1}.com")

# both tests run in paralell
# it is necessary to mark the test as async
Expand Down
5 changes: 4 additions & 1 deletion examples/web_ui/playwright/pages/getting_started.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,7 @@ def __init__(self, driver):

def do(self, **kwargs):
self._driver.get_by_role("link", name="Writing tests", exact=True).click()
return self._driver.get_by_role("heading", name="Writing Tests").text_content()
return self._driver.get_by_role(
"heading",
name="Writing ",
).text_content()
3 changes: 2 additions & 1 deletion examples/web_ui/selenium/advanced/test_external_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ def test_vpm_transaction_chain(self):
it.IsEqualTo, content_in_portuguese
)
# uses native assertion
assert self._app.at(home.ChangeToEnglish).result == content_in_english
result = self._app.at(home.ChangeToEnglish).result
it.IsEqualTo().asserts(result, content_in_english)
self._app.at(info.NavigateTo).asserts(
it.Contains,
(
Expand Down
47 changes: 36 additions & 11 deletions guara/it.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,52 @@
import logging
from typing import Any

LOGGER = logging.getLogger(__name__)


class IAssertion:
def asserts(self, actual: Any, expected: Any) -> None:
def asserts(self, actual: Any, expected: Any) -> bool | AssertionError:
raise NotImplementedError

def validates(self, actual, expected):
LOGGER.info(f"Assertion '{self.__class__.__name__}'")
try:
result = self.asserts(actual, expected)
LOGGER.info(f" actual: '{actual}'")
LOGGER.info(f" expected: '{expected}'")
return result
except Exception:
LOGGER.error(f" actual: '{actual}'")
LOGGER.error(f" expected: '{expected}'")
raise


class IsEqualTo(IAssertion):
def asserts(self, actual, expected):
assert actual == expected
if actual == expected:
return True
raise AssertionError


class IsNotEqualTo(IAssertion):
def asserts(self, actual, expected):
assert actual != expected
if actual != expected:
return True
raise AssertionError


class Contains(IAssertion):
def asserts(self, actual, expected):
assert expected in actual
if expected in actual:
return True
raise AssertionError


class DoesNotContain(IAssertion):
def asserts(self, actual, expected):
assert expected not in actual
if expected not in actual:
return True
raise AssertionError


class HasKeyValue(IAssertion):
Expand All @@ -39,7 +62,7 @@ class HasKeyValue(IAssertion):
def asserts(self, actual, expected):
for k, v in actual.items():
if list(expected.keys())[0] in k and list(expected.values())[0] in v:
return
return True
raise AssertionError


Expand All @@ -54,8 +77,9 @@ class MatchesRegex(IAssertion):
def asserts(self, actual, expected):
import re

if not re.match(expected, actual):
raise AssertionError
if re.match(expected, actual):
return True
raise AssertionError


class HasSubset(IAssertion):
Expand All @@ -67,8 +91,9 @@ class HasSubset(IAssertion):
"""

def asserts(self, actual, expected):
if not set(expected).intersection(actual) == set(expected):
raise AssertionError
if set(expected).intersection(actual) == set(expected):
return True
raise AssertionError


class IsSortedAs(IAssertion):
Expand All @@ -80,4 +105,4 @@ class IsSortedAs(IAssertion):
"""

def asserts(self, actual, expected):
IsEqualTo().asserts(actual, expected)
return IsEqualTo().asserts(actual, expected)
5 changes: 1 addition & 4 deletions guara/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ def asserts(self, it: IAssertion, expected):
"""The `asserts` method receives a reference to an `IAssertion` instance.
It implements the `Strategy Pattern (GoF)` to allow its behavior to change at runtime.
It validates the result using the `asserts` method."""
LOGGER.info(f"Assertion '{it.__name__}'")
LOGGER.info(f" actual: '{self._result}'")
LOGGER.info(f" expected: '{expected}'")

it().asserts(self._result, expected)
it().validates(self._result, expected)
return self
24 changes: 12 additions & 12 deletions tests/test_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


def test_assert_is_equal():
assert it.IsEqualTo().asserts("any", "any") is None
assert it.IsEqualTo().asserts("any", "any") is True


def test_assert_is_equal_raises_exception():
Expand All @@ -12,7 +12,7 @@ def test_assert_is_equal_raises_exception():


def test_assert_is_not_equal():
assert it.IsNotEqualTo().asserts("any", "other") is None
assert it.IsNotEqualTo().asserts("any", "other") is True


def test_assert_is_not_equal_raises_exception():
Expand All @@ -21,7 +21,7 @@ def test_assert_is_not_equal_raises_exception():


def test_assert_contains():
assert it.Contains().asserts("any other", "any") is None
assert it.Contains().asserts("any other", "any") is True


def test_assert_contains_raises_exception():
Expand All @@ -30,7 +30,7 @@ def test_assert_contains_raises_exception():


def test_assert_does_not_contain():
assert it.DoesNotContain().asserts("any other", "foo") is None
assert it.DoesNotContain().asserts("any other", "foo") is True


def test_assert_does_not_contains_raises_exception():
Expand All @@ -41,27 +41,27 @@ def test_assert_does_not_contains_raises_exception():
def test_assert_has_key_value():
actual = {"any-key": "any-value", "other-key": "other-value"}
expected = {"any-key": "any-value"}
assert it.HasKeyValue().asserts(actual, expected) is None
assert it.HasKeyValue().asserts(actual, expected) is True


def test_assert_has_key_value_raises_exception():
actual = {"any-key": "any-value", "other-key": "other-value"}
expected = {"no-key": "no-value"}
with pytest.raises(AssertionError):
assert it.HasKeyValue().asserts(actual, expected) is None
assert it.HasKeyValue().asserts(actual, expected) is True


def test_assert_matches_regex():
actual = "An explanation of your regex will be automatically generated as you type"
expected = "An explanation of your regex will (.*)"
assert it.MatchesRegex().asserts(actual, expected) is None
assert it.MatchesRegex().asserts(actual, expected) is True


def test_assert_matches_regex_raises_exception():
actual = "An explanation of your regex will be automatically generated as you type"
expected = "do not match anything"
with pytest.raises(AssertionError):
assert it.MatchesRegex().asserts(actual, expected) is None
assert it.MatchesRegex().asserts(actual, expected) is True


def test_assert_is_subset_list():
Expand All @@ -86,7 +86,7 @@ def test_assert_is_subset_list():
"be",
"automatically",
]
assert it.HasSubset().asserts(actual, expected) is None
assert it.HasSubset().asserts(actual, expected) is True


def test_assert_is_subset_list_raises_exception():
Expand Down Expand Up @@ -114,7 +114,7 @@ def test_assert_is_subset_list_raises_exception():
"automatically",
]
with pytest.raises(AssertionError):
assert it.HasSubset().asserts(actual, expected) is None
assert it.HasSubset().asserts(actual, expected) is True


def test_assert_is_sorted_list():
Expand Down Expand Up @@ -146,7 +146,7 @@ def test_assert_is_sorted_list():
"you",
"type",
]
assert it.IsSortedAs().asserts(actual, expected) is None
assert it.IsSortedAs().asserts(actual, expected) is True


def test_assert_is_sorted_list_raises_exception():
Expand Down Expand Up @@ -179,4 +179,4 @@ def test_assert_is_sorted_list_raises_exception():
"An",
]
with pytest.raises(AssertionError):
assert it.IsSortedAs().asserts(actual, expected) is None
assert it.IsSortedAs().asserts(actual, expected) is True

0 comments on commit d1e24f1

Please sign in to comment.