#unit-testing
1 messages · Page 26 of 1
yeah, you just need to pass few more arguments/flags to settings during selenium initialization
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("--headless")
driver = webdriver.Chrome(executable_path="./chromedriver",
options=chrome_options)
Hello, could i get some resources to learn testing?
Maybe this book?
https://www.obeythetestinggoat.com/
Can't personally recommend because I haven't read it yet but I heard good things.
ok thanks
hey
I was trying to install pytest
check this out.
(base) feynman@legion-ayush:~$ pytest --version
bash: /usr/bin/pytest: No such file or directory
Its searching for pytest in /usr/bin
(base) feynman@legion-ayush:~$ pip install -U pytest
Requirement already satisfied: pytest in ./anaconda3/lib/python3.7/site-packages (6.2.5)
Requirement already satisfied: attrs>=19.2.0 in ./anaconda3/lib/python3.7/site-packages (from pytest) (21.2.0)
Requirement already satisfied: importlib-metadata>=0.12 in ./anaconda3/lib/python3.7/site-packages (from pytest) (3.10.0)
Requirement already satisfied: py>=1.8.2 in ./anaconda3/lib/python3.7/site-packages (from pytest) (1.10.0)
Requirement already satisfied: pluggy<2.0,>=0.12 in ./anaconda3/lib/python3.7/site-packages (from pytest) (0.13.1)
Requirement already satisfied: packaging in ./anaconda3/lib/python3.7/site-packages (from pytest) (21.0)
Requirement already satisfied: toml in ./anaconda3/lib/python3.7/site-packages (from pytest) (0.10.2)
Requirement already satisfied: iniconfig in ./anaconda3/lib/python3.7/site-packages (from pytest) (1.1.1)
Requirement already satisfied: zipp>=0.5 in ./anaconda3/lib/python3.7/site-packages (from importlib-metadata>=0.12->pytest) (3.5.0)
Requirement already satisfied: typing-extensions>=3.6.4 in ./anaconda3/lib/python3.7/site-packages (from importlib-metadata>=0.12->pytest) (3.10.0.0)
Requirement already satisfied: pyparsing>=2.0.2 in ./anaconda3/lib/python3.7/site-packages (from packaging->pytest) (2.4.7)
I seem to have pytest, but not in usr/bin
what do I do?
(base) feynman@legion-ayush:~$ which python
/home/feynman/anaconda3/bin/python
its the one where pytest is
Should be here then /home/feynman/anaconda3/bin/pytest
What's your $PATH?
And deactivating and deactivating you virtual environment should do it
no its not there either
im not using a venv actually
how do I find this out?
(base) feynman@legion-ayush: looks like an activated virtual environment to me
echo $PATH I think
(base) feynman@legion-ayush:~$ echo $PATH
/home/feynman/anaconda3/bin:/home/feynman/anaconda3/condabin:/home/feynman/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Wait it's not here? Try uninstalling pytest and upgrading pip setuptools wheel then installing pytest again
it says requirement already satisfied when I try installing pytest
/home/feynman/anaconda3/bin/python -m pip uninstall pytest
/home/feynman/anaconda3/bin/python -m pip install -U pip setuptools wheel
i uninstalled, and installed and it says the same thing lol
alright lemme do this agian
Show the full output
Found existing installation: pytest 6.2.5
Uninstalling pytest-6.2.5:
Would remove:
/home/feynman/anaconda3/bin/py.test
/home/feynman/anaconda3/bin/pytest
/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/*
/home/feynman/anaconda3/lib/python3.7/site-packages/pytest-6.2.5.dist-info/*
/home/feynman/anaconda3/lib/python3.7/site-packages/pytest/*
Proceed (Y/n)? y
Successfully uninstalled pytest-6.2.5
(base) feynman@legion-ayush:~$ /home/feynman/anaconda3/bin/python -m pip uninstall pytest
WARNING: Skipping pytest as it is not installed.
Now installing it again.
Collecting pytest
Using cached pytest-6.2.5-py3-none-any.whl (280 kB)
Requirement already satisfied: toml in ./anaconda3/lib/python3.7/site-packages (from pytest) (0.10.2)
Requirement already satisfied: pluggy<2.0,>=0.12 in ./anaconda3/lib/python3.7/site-packages (from pytest) (0.13.1)
Requirement already satisfied: iniconfig in ./anaconda3/lib/python3.7/site-packages (from pytest) (1.1.1)
Requirement already satisfied: py>=1.8.2 in ./anaconda3/lib/python3.7/site-packages (from pytest) (1.10.0)
Requirement already satisfied: importlib-metadata>=0.12 in ./anaconda3/lib/python3.7/site-packages (from pytest) (3.10.0)
Requirement already satisfied: packaging in ./anaconda3/lib/python3.7/site-packages (from pytest) (21.0)
Requirement already satisfied: attrs>=19.2.0 in ./anaconda3/lib/python3.7/site-packages (from pytest) (21.2.0)
Requirement already satisfied: typing-extensions>=3.6.4 in ./anaconda3/lib/python3.7/site-packages (from importlib-metadata>=0.12->pytest) (3.10.0.0)
Requirement already satisfied: zipp>=0.5 in ./anaconda3/lib/python3.7/site-packages (from importlib-metadata>=0.12->pytest) (3.5.0)
Requirement already satisfied: pyparsing>=2.0.2 in ./anaconda3/lib/python3.7/site-packages (from packaging->pytest) (2.4.7)
Installing collected packages: pytest
Successfully installed pytest-6.2.5
(base) feynman@legion-ayush:~$ pytest --version
bash: /usr/bin/pytest: No such file or directory
Same issue
Oh and btw, import pytest is working
base) feynman@legion-ayush:~$ python
Python 3.7.11 (default, Jul 27 2021, 14:32:16)
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pytest
>>>
Weird stuff.
(base) feynman@legion-ayush:~$ /home/feynman/anaconda3/bin/pytest
Traceback (most recent call last):
File "/home/feynman/anaconda3/bin/pytest", line 8, in <module>
sys.exit(console_main())
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/config/__init__.py", line 185, in console_main
code = main()
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/config/__init__.py", line 143, in main
config = _prepareconfig(args, plugins)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/config/__init__.py", line 319, in _prepareconfig
pluginmanager=pluginmanager, args=args
File "/home/feynman/anaconda3/lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
return self._hookexec(self, self.get_hookimpls(), kwargs)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/pluggy/manager.py", line 93, in _hookexec
return self._inner_hookexec(hook, methods, kwargs)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/pluggy/manager.py", line 87, in <lambda>
firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
File "/home/feynman/anaconda3/lib/python3.7/site-packages/pluggy/callers.py", line 203, in _multicall
gen.send(outcome)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/helpconfig.py",
line 100, in pytest_cmdline_parse
config: Config = outcome.get_result()
File "/home/feynman/anaconda3/lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
raise ex[1].with_traceback(ex[2])
File "/home/feynman/anaconda3/lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
res = hook_impl.function(*args)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/config/__init__.py", line 1003, in pytest_cmdline_parse
self.parse(args)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/config/__init__.py", line 1283, in parse
self._preparse(args, addopts=addopts)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/config/__init__.py", line 1172, in _preparse
self.pluginmanager.load_setuptools_entrypoints("pytest11")
File "/home/feynman/anaconda3/lib/python3.7/site-packages/pluggy/manager.py", line 299, in load_setuptools_entrypoints
plugin = ep.load()
File "/home/feynman/anaconda3/lib/python3.7/site-packages/importlib_metadata/__init__.py", line 167, in load
module = import_module(match.group('module'))
File "/home/feynman/anaconda3/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "/home/feynman/anaconda3/lib/python3.7/site-packages/_pytest/assertion/rewrite.py", line 170, in exec_module
exec(co, module.__dict__)
File "/home/feynman/anaconda3/lib/python3.7/site-packages/web3/__init__.py", line 6, in <module>
from eth_account import (
File "/home/feynman/anaconda3/lib/python3.7/site-packages/eth_account/__init__.py", line 1, in <module>
from eth_account.account import ( # noqa: F401
File "/home/feynman/anaconda3/lib/python3.7/site-packages/eth_account/account.py", line 11, in <module>
from eth_keyfile import (
File "/home/feynman/anaconda3/lib/python3.7/site-packages/eth_keyfile/__init__.py", line 7, in <module>
from eth_keyfile.keyfile import ( # noqa: F401
File "/home/feynman/anaconda3/lib/python3.7/site-packages/eth_keyfile/keyfile.py", line 7, in <module>
from Crypto.Protocol.KDF import scrypt
ImportError: cannot import name 'scrypt' from 'Crypto.Protocol.KDF' (/home/feynman/anaconda3/lib/python3.7/site-packages/Crypto/Protocol/KDF.py)
What does it have to do with Crypto.Protocol.KDF!
I googled that bit and that error only occurs to guys working with the web3 module
!paste
Pasting large amounts of code
If your code is too long to fit in a codeblock in discord, you can paste your code here:
https://paste.pythondiscord.com/
After pasting your code, save it by clicking the floppy disk icon in the top right, or by typing ctrl + S. After doing that, the URL should change. Copy the URL and post it here so others can see it.
looks like you have the wrong Crypto installed https://github.com/ethereum/web3.py/issues/751#issuecomment-379477011
how can i use a factory with return values on mocks?
eg on https://docs.python.org/3/library/unittest.mock.html I want to set a return_value to return a different object each time the method is called. It just needs to create the object every time i call that mocked method
Use side_effect
ahhh, okay
trying to fully mock objects, as automatic as i can get it
onto type hinting to get them into side_effect
it also depends on what exactly you're trying to do
"fully mocking objects" seems like a bad idea in a lot of cases
i prefer mocking as little as possible
but maybe you are doing mocking some enormous auto-geneated swig stuff and there's no sensible way to go about it otherwise
http://swig.org/ makes one want to swig wine, yes
Like swing?
it's a c++ binding generator
hey, i'm using pytest and travis-ci to test my github repo and forgot that dataclasses are not supported by python 3.6. i have searched the crawlers, the travis-ci docs, and read quite a few blogs, but feel like i'm missing something insanely simple. is there a way to install just the dataclasses module as a dep for only python 3.6 on travis-ci so that my tests can pass?
hello, I would like to test websites with python/selenium, what would you recommend me as library to manage those tests, generate reports etc .... thanks
pytest / unittest / robot ... ?
@pallid radish depends on your use case. i would recommend pytest though. i liked unittest, but it's very simple and web apps tend to grow in complexity and pytest scales with that complexity really well. alot better than unittest does. the difference is that w/ unittest, you'll have to manually implement alot of the stuff the pytest automates for you.
@pallid radish You might wanna read this discords help docs. they recommend against asking generalized questions and instead recommend asking very specific questions according to what you're asking. you're question is very general and hard to answer because, it just depends. its better to dyor on this one.
ok thank you, yes it's a bit "generalized" question .... yet you answered perfectly to my question, so I will begin with pytest
Should tests be completely isolated? For example if I need to create a subclass, should this be done inside the test function?
@frigid basalt a unit test shouldn't reuse stuff from a previous test. (unless you're explicitly testing a scenario step-by-step and stopping when the first one fails, but that's not called a unit test any more)
If you find yourself creating the same stuff for many tests, instead of repeating yourself in each test function, you can create a "test fixture" with a setup method that will be run from scratch before each test method.
https://docs.python.org/3.9/library/unittest.html?#organizing-tests
Hmm, thank you
if you need to test something like a decorator, imo it's very reasonable to create the subclass right inside the test method
Going back to my question in #type-hinting, what I do is I create a DummyEvent subclass in almost every test 😬
in my experience sometimes that's just the way things go. other times, if a test has a complicated setup, you can make a whole bunch of assertions in the same test method. it's not really a "unit" test anymore, but you are still testing individual units - just not as individual test methods
I wanted to create it inside the file, since it essentially holds no state being clearly only a class
That's actually something I was considering asking about, I have a test like this: ```python
def test_non_registered(self):
"""Test that ValueError is raised when a listener isn't registered."""
class DummyEvent(Event):
name = 'DUMMY'
dispatcher = EventDispatcher()
async def callback(event: DummyEvent):
...
with pytest.raises(ValueError):
dispatcher.remove_listener(callback)
with pytest.raises(ValueError):
dispatcher.remove_listener(callback, event=DummyEvent)
with pytest.raises(ValueError):
dispatcher.remove_listener(callback, event=DummyEvent.name)
It seemed pretty dumb to copy this over for all of those. But yeah it's not *really* a unit test anymore
meh, this is where i give the finger to formalism and just write the tests
but i also tend to write long-form comments explaining why i did things the way i did them
with my initials and the date at the bottom, so you can tell if it's out of date + people know who to message/email if there's a question
that said, in particular case you can set that up as a fixture, or just write a helper function to do it
but personally i'd probably write a test just like the example you posted
your'e still testing one unit of functionality imo
you are just making several assertions about it
you don't have to have 1 assertion per method
How does that work? I am literally new to unit testing and trying to find my way around it by unit testing an event dispatcher 😅
one option that is very unittest-ey:
class TestEventDispatcher:
def setUp(self):
# A fresh DummyEvent class for each test method
class DummyEvent(Event):
name = 'DUMMY'
self.DummyEvent = DummyEvent
# A fresh EventDispatcher instance for each test method
self.dispatcher = EventDispatcher()
def test_non_registered(self):
"""Test that ValueError is raised when a listener isn't registered."""
async def callback(event): pass
with pytest.raises(ValueError):
self.dispatcher.remove_listener(callback)
with pytest.raises(ValueError):
self.dispatcher.remove_listener(callback, event=self.DummyEvent)
with pytest.raises(ValueError):
self.dispatcher.remove_listener(callback, event=self.DummyEvent.name)
decorator for what?
Isn't it called like parameterize?
that's for pytest
and parametrize is not exactly the same thing, although you can think of it as an ad-hoc locally-defined fixture
a "fixture" is a general concept, although pytest has its very specific (and imo very weird and kind of unpleasant) notion of fixtures
i like almost everything else about pytest, but the fixture stuff is way too automagical for me, i'd rather have an explicit decorator for fixtures instead of relying on the parameter name
I just use the decorator way
regardless, you don't need it in unittest
How does it work there then?
well, there's no unified framework for fixtures in unittest
you can use setUp() and setupClass() to set up test-scoped or class-scoped fixtures
and their corresponding methods tearDown() and tearDownClass()
So you create your own decorators then?
you could do that
you don't have to use a decorator
hypothesis and unittest.mock.patch can be used as decorators
seems like a rather complex way to assign parameter values iirc you have to give a string like "arg1 arg2 arg3" to the decorator
probably so you can supply any set of args using rows of tuples
that's parameterize, and you can use a tuple of strings. different magic
@pytest.fixture
def foo():
return 1
def test_something(foo):
assert foo == bar()
pytest fixtures are like that
or something like that anyway
too magical for me, i'd rather explicitly write it out
@pytest.fixture
def foo():
return 1
# hypothetical
@with_fixture(foo)
def test_something(foo):
assert foo == bar()
parametrize is weird the first time you see it, but if you want to check lots of cases it's very nice
yeah it does work really well
I also thought that pytest's fixtures were a little too magical at first but after working with them for a while I don't mind them; pycharm will take you to the fixture definition when you click the param which helps a lot
Should I be testing all cases of my code and errors?
I can't help but feel like I am simply testing the implementation
Isn't there some saying that you should like "test the effect not the implementation"
sure. your code has branches of logic.
Usually we try to write it as happy main path
but sometimes it has a lot of if conditions that makes it multibranching
we test different branches of the code logic
===
plus sometimes we can think about the testing as just black box testing.
we don't know the code, we just input different edging input values and check the results, that's it
for example if your code allows as input values from 2 to 10. we tried 5, 0 and 12 to input and that's it. Whatever logic inside we don't care
===
and a third approach.
there is usually in your code separation between...
view logic, business domain logic and some implementation-low level logic
for example the most important to test business logic (the tests... are basically business scenarios), everything is else is usually less important.
===
black box testing is usually the easiest to be done and the most refactor resilient (after main code refactorizations, less changes to tests are needed) ;b
Are code that tests good input better than code that test for errors or similar?
That's something I've run into, it feels like I am just creating tests to run the error-cases of bad behaviour
I am not sure if I can explain everything, but this book can
there is a good thing to test your code only for input and output
because:
less attachements to implementations ->
-> less fragile tests ->
-> less refactorizations to testing code
you should test both. you never know when someone will break what you thought was an "obviously correct" code path
i've never regretted writing a test for a "good" input - if those tests break, then you really know you fucked up
well, considering that error outputs are still error outputs... if we test input and output, we would test error outputs too
obviously... if there is something like a rule, that one email should not be able to register twice, we need to test registering with same email twice and checking for the error
we just input email twice ;b and check the output for error in this case
Oh I mean the other way around!
It seems somewhat unnecessary to make tests for bad input?
It's not expected behaviour and all it does it reveal more of the implementation
To fully test my method I need to look at the implementation and write tests that reach each branch or execution
Guys I need some help. Wrote a few unit test which detects if my sklearn model outputs the same number given the same seed and input
It works on my local machine, but when I went up to Microsoft Azure, the random numbers became different despite having the same seed
Does different machine create different floating point error or something?
TL Dr, unit test doesn't work across different machine despite having checked very thoroughly that they all have the same random state
it depends on which errors i think
if those errors are important for business/domain logic of the application
then surely it is important to test them
although you know, it is better to test all errors that users will see 🤔
but the priority can be made for which ones are important and which less
Yes.
probably not what you should be testing
possibly.
or different OS
your test is way too granular
there's this saying
"tests can only show the presence, and not the absence, of bugs"
minimally you should write tests to show that the happy case, as well as a few expected "bad" cases, are handled correctly
but it depends on what level of testing you're performing
in general, @ very high levels (acceptance tests), what you care about is more that the user is able to do something
e.g. "can sign up for a class"
Hmm, yeah
To be fair, it does give me a pretty good evidence for my boss not to expect the same numbers
Although, what would be a good example for what I should be testing? Perhaps something like "this algorithm does reduce feature to an expected amount"?
are you familiar with the various terms people use to describe testing?
like unit, integration, contract, acceptance, E2E
!code
for a give function:
def foo(self):
try
bar()
except
I'm supposed to write an unit test:
I've mocked the bar function and tested the foo. Caveat here being that I'm somehow supposed to trigger the except part, however, bar does not contain any raises. How can I achieve this, keeping in mind that bar is as of this time mocked?
Hello all,
I was trying to make a profiler in Python and i ve failed many times until i ve finally got it with an offical CProfiler from the Python documentation.
I am using it as a decorator and i am obviously pasting it above each function that i want to profile, and the report that i get is too long and therefore i can not read it from the console.
Since every single profiler visualisation tutorial on the internet is running CProfiler from a console by running a file and not decorating it as i am doing it, i can not find a solution to make it, so i am here asking you for help.
Thanks so much in advance!
hey, im new at unit testing and i saw that there are 2 libs that i can use: pytest and unittest
id like to know which one of there two is considered the "best" in terms of documentation, clean code (if applicable), etc
Tried searching it on google
Only the first two. Unfortunately until the last month, I've been using python to perform statistical analysis and the standards in my team aren't very good as everything was at its starting stage. So initially there was absolutely no good practice. I'm trying to change this of course.
I only know unit test test the most basic functions. And integration test are how these function should behave when integrated together
My colleague introduced me to a simple example where I call a function with predefined input, and end that test with a assert np.isclose(result, expected_result)
So I've been using that mostly
Contract acceptance and e2e, I have only heard of that from you
Quick Google search gave me understanding of contract and E2E, though acceptance still sounds arcane to me
okay this is kind of complex and right now I lack the mental bandwidth to elaborate
but if you are serious about it, I suggest doing (a lot of) research on "how to test" and "what to test"
I am using pytest to test a mixin, and I want to run all tests on a few of the classes that implement this test. Which means tests may be ran multiple times
How would I create a fixture to do this?
I was considering using parameterize on the class-level to apply on all tests.. but that means that instances of the class is shared (unless I just pass the class I guess?)
Y'know, I'll probably just do that nvm
Tl; Dr, I'm not in a tech company and every programmer including me is on their own.
Honestly, I don't think my test was "bad". It definitely followed the AAA principle. I just need to realize that I shouldn't be expecting a reproducibility from a random algorithm.
I just need more experience and mileage
can any one help me run this source code ?
https://github.com/niladri30/Face-Recognition-Raspberry-pi
Im currently a newb in python i mean learning 2% noob
i just want to run test the py code of this source code
Help is much appreciated
Is it a bad thing when test files are 2x longer than the file they're testing??
definitely not imo. you could probably do some refactoring for the test to reuse helper functions etc, and it is good that the implementation of a functionality is shorter, but it's rarely bad to test too much
Do people typically write tests for properties of functions? Eg, we might want all functions written for a particular module to be idempotent - and to test that is the case. I'm wondering if there's a typical way to go about this sort of testing though, perhaps there's a name for testing the properties of functions and not just their behaviours
I get that if i have something like:
def f(x):
if x % 2 == 1:
return x + 1
return x
Then I could check idempotent with something like:
assert f(3) != 3
assert f(f(3)) == f(3)
not sure if there are standard approaches to this though
I'm not sure regarding your first question, but I don't think you can check for idempotence while treating the func as a black box
consider:
>>> vec = []
>>> def add_one(n):
... vec.append(n)
... return n + 1
...
the state of the program changes every time you call this function, but it's not observable from the return value alone
not necessarily a bad thing
actually most of my test files are longer than the implementations
that's not the only characteristic of a good test
it doesn't for example, talk about determinism (which was exactly the problem)
but in this case it's not really just that...
the question is - what are you really testing?
@ lower levels of integration and abstraction it's easy to say a function works or does not work
but what does it mean to say a model "works"?
if it's a language problem, does it make sense to assert bleu_score > 4.0?
I definitely was testing for determinism.
It does test if all the underlying "random state" parameter are set to something and not a "None" value as well, which didn't fail. This test if it's default behaviour defaults to the one I intended it to be.
As for everything else, it wasn't really something under my control (it's sklearn model) so I didn't test those.
Although, what really bothers me is I want the answer of "what should I test then?" When you suggest this
I'm testing out RandomForestClassifier fyi
true, as this function has side effects, which is something i'm not too sure how to test for 😅
run the function one thousand times, something is bound to break
if vec isn't used anywhere else it would be hard to spot by writing tests alone, unless you look into the code itself and check for themodule.vec from the test, but by looking at the code you'd probably spot the problem already. Either way, if you have linting it will probably warn you about something like this in most cases
Guys how do I setup a test database for backend tests with pytest and docker?
which framework and databaase library access u a using
in django there is a setting for this
for the others - Idk
django is so cool; I was fretting about how to do model tests but yeah, just change the db backend to sqlite and everything works the same
you don't even need to change the db...if you're using something else, like postgres, it will create and tear down a test_database
true, but that requires a database already set up, so sqlite is useful in that case
oh yea. I thought you meant you changed it for testing.
Flask + pytest
hm I would not recommend this
it's better to have your test env mirror your prod env as much as possible
supporting the msg above.
When I started testing in target db: postgresql, instead of sqlite
I quickly discovered thay my code is not working, because postgresql has working constraints (limiting amount of symbols in a variable, having only unique values and etc) and sqlite does not have.
yes
in this project I had no control over our build infra, which did not have postgres (╯°□°)╯︵ ┻━┻
how y'all like my tests
it's for a function to count how many consonants & vowels are in a sentence lol
I think they need parametrization
https://docs.pytest.org/en/latest/how-to/parametrize.html
@pytest.mark.parametrize(
"phrase ,constants_amount, vowels_amount", (
("Among Us", 3,4),
("Padme", 2,3),
('', 0, 0),
(['List'], 1, 3)
)
)
def test_howmany_consonants_and_vowels_in_English_sentence(phrase, constants_amount, vowels_amount):
assert vcc(English, phrase) == (constants_amount, vowels_amount)
Sir, it is a crime to neglect adding the diacritics in Padmé Amidala's name
It interferes with testing it's ability to handle diacritics
no idea what it is, but I'll trust your words about it
I get offended when somebody does not type in the e properly in Padmé Amidala's name
é not e
i am just kidding, i can read the letters
@maiden pawn don't forget all 4 normalization forms!
ergh? what?
import unicodedata
from functools import partial
to_nfc = partial(unicodedata.normalize, 'NFC')
to_nfd = partial(unicodedata.normalize, 'NFD')
to_nfkc = partial(unicodedata.normalize, 'NFKC')
to_nfkd = partial(unicodedata.normalize, 'NFKD')
@pytest.mark.parametrize(
"phrase ,constants_amount, vowels_amount", (
("Among Us", 3,4),
(to_nfc("Padmé"), 2,3),
(to_nfd("Padmé"), 2,3),
(to_nfkc("Padmé"), 2,3),
(to_nfkd("Padmé"), 2,3),
('', 0, 0),
(['List'], 1, 3)
)
)
def test_howmany_consonants_and_vowels_in_English_sentence(phrase, constants_amount, vowels_amount):
assert vcc(English, phrase) == (constants_amount, vowels_amount)
Specifies the Unicode Normalization Formats
I think doubled parametrization should be possible.
!e ```python
import unicodedata
text = 'Padmé'
enc1 = unicodedata.normalize('NFC', text).encode('utf-8')
enc2 = unicodedata.normalize('NFD', text).encode('utf-8')
print(enc1)
print(enc2)
@pearl cliff :white_check_mark: Your eval job has completed with return code 0.
001 | b'Padm\xc3\xa9'
002 | b'Padme\xcc\x81'
👆 more advices for some sort of normalizations for you
yeah i imagine there's some tidy way to chain parameterizations, otherwise you can do it with itertools things or write your own helper functions
@sinful hill
import unicodedata
from functools import partial
@pytest.mark.parametrize("normalization", ('NFC', 'NFD', 'NFKC', 'NFKD'))
@pytest.mark.parametrize(
"phrase ,constants_amount, vowels_amount", (
("Among Us", 3,4),
("Padmé", 2,3),
('', 0, 0),
(['List'], 1, 3)
)
)
def test_howmany_consonants_and_vowels_in_English_sentence(normalization, phrase, constants_amount, vowels_amount):
normalizator = partial(unicodedata.normalize, normalization)
assert vcc(English, normalizator(phrase)) == (constants_amount, vowels_amount)
if it will work
tldr you can either write the single unicode codepoint LATIN SMALL LETTER E WITH ACUTE (\u00e9), or the sequence of codepoints LATIN SMALL LETTER E COMBINING ACUTE ACCENT (\u0065 \u0301)
the former is "composed" and the latter is "decomposed"
tell it to lemuria
it is not me who does it
I just adviced about parametrization)
@pearl cliff :white_check_mark: Your eval job has completed with return code 0.
001 | é
002 | é
Well, it's a crime to spell Padmé Amidala's name without the acute é...
Or at least it should be
How do I access mappings when unit testing? I cant seem to figure it out
hey guys, I'm writing a few tests rn
def test_check_password(user: User, faker: Faker):
"""
Ensure we can verify an user's password.
"""
password = faker.password(length=12)
user.set_password(password=password)
assert user.check_password(password=password)
assert not user.check_password(password="someotherpassword")
In this pytest test case (which uses faker), is there any way that I don't have to hardcode the "someotherpassword" string and still make the tests pass consistently?
Generate another one with faker?
So do other_password = faker.password(length=12) but don't use the set_password()
this is a great use for hypothesis
@hypothesis.given(st.text(), st.text())
def test_check_password(password, other):
"""Ensure we can verify an user's password."""
hypothesis.assume(password != other)
user.set_password(password=password)
assert user.check_password(password=password)
assert not user.check_password(password=other)
Hey, I am trying to test following scenario:
class Foo:
def __init__(self, bar):
self.bar = bar
def do_stuff(self):
self.bar.fun()
test attempt using unittest:
import unittest
import bar
class ATestCase(TestCase):
def test_do_stuff(self):
# given
mock_bar = MagicMock()
mock_bar.fun = MagicMock()
test_foo = Foo(mock_bar)
# when
test_foo.do_stuff()
# then
mock_bar.fun.assert_called()
is there shorter way to mock attributes like mock_bar.fun? Ideally a one-liner
in js using jest it is possible to mock objects like const a = {fun: jest.fn()}, I'm looking for something similar
I would've thought you could just chain
!e
from unittest.mock import MagicMock
a = MagicMock()
a.b.c.assert_called()
@magic dawn :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 5, in <module>
003 | File "/usr/local/lib/python3.10/unittest/mock.py", line 888, in assert_called
004 | raise AssertionError(msg)
005 | AssertionError: Expected 'c' to have been called.
yeah there we go
When we write tests,is it the output we're testing for or the logic that brings the output? From the tutorials I've gone through (10+), It seems tests are concerned with the output. I'm new to this, and I've always thought it's the logic that's being tested and not the output.
You test the logic using the output
Or the side effects
@rocky ermine how would you test a function without looking at the output or side effects?
Honestly, I have no clue. I'm using the thought process from a year ago when I attempted to write tests. Now that I've gone through several articles it seems I was just doing nonsense. Lol
?
I was basically rewriting the logic uniquely for the test, for whatever dumb reason I could think of.
the test class has a rewritten logic, which isn't the right way to go about it from what I've read. Thanks.
Well that's something you can use in hypothesis
Eg if you're writing an optimal algorithm you'd compare it against a naive implementation
how to write a function that receive an image and returns the image in black and white using python np.average?
This isn't the right channel for that, try #❓|how-to-get-help
How do I test a post endpoint without sending data from the post endpoint? I don't want to fill the dB with nonsense.
Most of the tutorials are testing get endpoints then mocking the data and response. Barely anything for post endpoints.
How are you running your app under test?
Usually you'd roll back your database after each test
I don't exactly have access to the dB. Everyone uses an API to read and write to the the dB.
If its not possible, I'll just tell them that we probably need mongo collection in the db for this kind of tests.
Seems like an integration test
I've just spend a few hours trying to figure out what is wrong with my test (already baseline scenario). It was failing when trying to run via python -m unittest foo.test.py on unittest library level with vague errors
It turned out it was because of filename, which included dot. When changed to foo_test.py it works correctly.
I tried to find such requirements in unittest docs, but I failed to find it. Can anyone help with finding reference?
The docs don't say much except that the test files have to be importable as a module... Just guessing but seems logical to me that dots are going to mess that up
Is there a reason not to use unittest and instead go for a different, external package? Usually I try to stick with what Python gives me to be independent of external packages but maybe ther might be reason to use pytest or nose or something?
Even Guido recommends you use pytest
Is there a reason behind that @hexed cloak?
pytest is better for mypy, for example
Generally if there's a pypi alternative of a built in you should use it and avoid the built in
It's a great goal to have, that's for sure.
my one complaint about pytest is the overly-magical fixture system... i wish you could request a fixture explicitly with a decorator, and turn off auto-requesting from parameter names
"explicit is better than implicit" basically
!e
def factorial(num, total=1):
if num == 1:
return total
else:
total*num
factorial(num-1, total)
result = factorial(5)
print(result)
Do you write docstrings for your tests?
yes, pytest and unittest can report the docstrings in output
Is there a way to have pretty graphs from running python -m unittest?
I tend not to bother unless it's some really weird edge case
I tend to have test function name fully describing the purpose of the test. The test function name can be as long as it is necessary.
That's my approach as well tbh
I find that can get unreadable, so I rely on the docstring to get more information across while keeping the test's name light.
Hiya! Is anyone 'round here familiar with the Factory-Boy library, and interested in helping to **proofread ** an article I wrote?
I'm a factory-boy noob and I spent a lot of time figuring out how to use it. I wanted to contribute to the pool of writing to help other new people learn it; I just finished my first draft yesterday :)
Okay, I need help from someone with a Mac; -;
Huge fan on Factory_Boy!
If I have a class:
class HTTPError(AblazeBaseException):
def __init__(self, response: ClientResponse, *args) -> None:
self.response = response
self.status = response.status
super().__init__(*args)
``` where its pointless to test because there just isnt really anything to test, is it ok in situations like this to tell coverage to ignore it, or is that a big no-no?
I don't think you should tell coverage to ignore it, that's just lying 😅.
Either suck up the not 100% coverage or simply instantiate it once y'know.
that's just lying 😅.
as opposed to making a test which instantiates it and doesnt do anything, which is just lying but more involved
I disagree, it's still helpful because you're testing that it can be instantiated. If you also try to raise that instance then you're testing that it is an exception that can be raised correctly.
don't think that's lying - just instantiating tests that the init is ok
you dont need to assert anything
Can't you run some code that actually raises it?
since the init in this case takes a ClientResponse, it should pass an object and assert that self.response is the passed response, and the status is the status of said response.
Since this derives from an Exception, it should also either: try to raise it
and/or: assert it subclasses Exception or any custom classes
@flint fiber ^
I feel like asserting that it is subclassing the right parent is a bit too strict unless the exception is designed for application code or something
depending on which test structure you use, a full test could be like this:
import unittest
import unittest.mock
class TestHTTPError(unittest.TestCase):
def test_init(self):
mock_response = unittest.mock.Mock()
error = HTTPError(mock_response)
self.assertIs(error.response, mock_response)
with self.assertRaises(HTTPError):
raise error
note: i use pytest, not unittest so this may not be accurate
Hi there, I'm a newbie in unit testing, I have this method that opens the file and makes some conditions then generate the output, what I wanna accomplish is to test this method, but the thing that I can't understand is, how can I test it while it's a static method, not I dynamic, what I mean is, It just has one specific file and I can't pass a file to it, so can anyone give me a hint how can I test it!
Why can't you pass a file to it?
myfiel seems like a typo
Also it prints "Python" for every subsequent line once it finds it?
you could make it take a string, instead of a file
that's what ,i would do, then it would be very easy to test. you could easily parameterize it
i have to assume this is just a sample, not your real function
since it doesn't do what it claims to do and it would give an UnboundLocalError, I think
but if you're making something testable, you also want your functions to return their output instead of printing
def parseSQL(sql):
output = ''
for line in sql.splitlines():
if line.find('Python'):
output = 'Python'
return output
import pytest
@pytest.mark.parametrize(
('sql', 'expected'), [
('select * from spam', ''),
('delete from Python where 1 = 1', 'Python'),
]
)
def test_parseSQL(sql, expected):
assert parseSQL(sql) == expected
def parseSQL(sql):
output = ''
for line in sql.splitlines():
if line.find('Python') != -1:
output = 'Python'
return output
``` ...then, you would run in a command line:
```bash
python -m pytest yourfile.py
``` That should be a basically a working example, hopefully it answers your question of how you would test your function
Where's the unbound local?
oh, I don't think there is one. didn't see the output = "" the first time, my bad 😁
he will just need to make a wrapper function in that case that prints the result
Right but for every line
wdym
The print happens for every line
my code is an example to show "how would I test this", it's not meant to be used verbatim
I'm sure t will need to be adapted
It's not clear what the function is supposed to do, it seems like it has been modified from the source before pasting here
exactly what I said
it doesn't have anything to do with SQL
so I assume it's just a contrived example, but who knows...
but the asker isn't answering our queries, so .. in hindsight, I wouldn't go near it
DISCLAIMER parseSql() us not to be imitated 😂 😂
basically it should more accurately be named foo or baz
Thanks guys
Hey all
Is there a way of passing environment variables defined in tox into the actual python code that is being tested?
That's what happens
Your grab it from os.environ
(Asked in main help with no luck, so I'm posting here)
I'm looking to develop tests/examples (not strictly unit tests) for a package I'm writing. I'm using a virtual environment to run my tests, and that's where my package and it's dependencies are installed.
The directory structure is
repo/
| -package_name/
| -__init__.py (imports package_name.module_1 and package_name.module_2)
| -module_1.py
| -module_2.py (imports module_1.py)
|-tests/
|-test.py (uses the package and one or more of the modules)
|-test_virtualenv/ (directory created by virtualenv)
|-setup.py (for making PyPI package)
I create the virtual environment with virtualenv , install my package (which gets the dependencies) using the virtual environment pip -e install., then deactivate.
When I want to run my tests I activate the environment, then loop over and run the Python files in tests , which is when I get the error.
File ....../module_2.py, line 2, in <module>
import module_1
ModuleNotFoundError: no module named 'module_1'
I can probably construct a simple failing case, but hopefully somebody could spot my issues before that. Thanks!
That's because you actually have an issue in your package
You need to either do from package_name import module_2 or from . import module_2
Thank you! This seems to mean that I can no longer run each of the module files of my package as standalone files (maybe I shouldn't have expected this in the first place?), which is a bit inconvenient for development. What's the proper workflow for this?
Well you see, that's the thing. You have to do either.
I usually have a Jupyter notebook at the same level as the package name folder (so next to setup.py) that imports the package and I then do the testing there.
Why do you need them to be separately working standalone files?
You can run it with python -m package_name.module_2
@frigid basalt I find it convenient when developing (and I dislike notebooks). But it's good to know I can't have it all, as that was my expectation.
@hexed cloak Yep, that works for my case, thank you!
I tend to just have one entry point using typer or similar
Then I put it in package_name/__main__.py
Then you use python -m package_name
pytest docs say:
Typos in function markers are treated as an error if you use the --strict-markers option.
Can I put something in pytest.ini to make this default behavior?
I added strict_markers = true and it didn't barf, so there's that
Actually it did once I started adding markers to tests:
PytestConfigWarning: Unknown config option: strict_markers
blarg
You need addopts = --strict-markers --strict-config
thank you
@torpid edge never ask to ask, just ask
oke
You might want to enable filterwarnings
i have some problem when coding bot music
can you say more? I think I understand what this does, but I'm not sure why I need it
Uhhhhhh sorry I got half way through the message and just sent it
np
pyproject.toml line 57
filterwarnings = ["error"]```
pyproject.toml line 55
xfail_strict = true```
python is a language where indentation is syntactically significant. if your indentation level doesn't make sense to the interpreter then it cannot execute your code.
that said, your question can probably go in another channel since it's not related to testing exactly... I'm not familiar enough with this discord to recommend a specific one though
@hexed cloak the idea is just to ensure that unhandled warnings are treated as test failures?
You should open a help channel see #❓|how-to-get-help
You can't really handle warnings, you can silence/ignore them
Right, that's what I should have said
But the idea is that if a warning is raised then the test should fail?
I can imagine situations where I wouldn't want that, but maybe it's best to enable that mode by default until there's a specific reason to ignore it
Right
Yep
Mainly a deprecation warning from a dependency that I have pinned, etc
Well you'd want to stop using the deprecated feature
There was one case where the next version up of a dependency irrevocably broke functionality that I needed so I couldn't upgrade it ever
But anyway, point is, paranoid defaults are good, thanks for the tip
Ah I see in this case I fork it
And use the fork for the bits that got removed
Yeah, it was just a toy project though, not worth maintaining a fork for a big module
diff --git c/pyproject.toml i/pyproject.toml
index fa19c5c..21d7ddc 100644
--- c/pyproject.toml
+++ i/pyproject.toml
@@ -50,7 +50,9 @@ isup = "downforeveryone.isup:main"
[tool.pytest.ini_options]
console_output_style = "progress"
-addopts = "--cov=downforeveryone"
+addopts = "--cov=downforeveryone --strict-markers --strict-config"
+filterwarnings = ["error"]
+xfail_strict = true
mock_use_standalone_module = true
[tool.poetry.dev-dependencies.isort]
@hexed cloak there you go
Did you get any warnings?
nope
Nice one
the code didn't raise any warnings before though, so now I'm curious how to test that this is doing what I tihnk it's doing
adding a randomraise Warning caused pytest to crap itself
this project is really cool. I'm so glad I never had to mess with python 2
It's warnings.warn
hmm still getting ERROR collecting test session
🤔
diff --git i/downforeveryone/__init__.py w/downforeveryone/__init__.py
index 5c4105c..3f33751 100644
--- i/downforeveryone/__init__.py
+++ w/downforeveryone/__init__.py
@@ -1 +1,5 @@
+import warnings
+
__version__ = "1.0.1"
+
+warnings.warn("no longer using your mom in the next version")
Well yeah that's what happens if you put a warning in an import
kek
"don't put code in __init__.py u fool"
okok
It seems I don't know what I'm doing
Hi guys. I hate unit tests.
It's like putting diapers on tons of old people, check them, change them. It's necessary to prevent shitty situations but it's still a shitty chore to do.
Tdd is okay until you are heading to a refactor. Today was the time to refactor some core parts and I want to die.
Good evening
IMO if tests require a rewrite after refactoring they aren't too great
depending on the scope of the refactor, ofc
I think TDD only makes sense if your "units" are big enough
true
and well, TDD helps for like, start state and end state. You know what the code needs to do, but it isn't always helpful
well said
In my experience, good "units" are more like what people would consider functional or integration tests
I do think it's worth having tests for internal functionality, but I think they should live in a separate module (or at least separate class) and they shouldn't be too complicated specifically because they might need to change
If only because user facing units tend to actually be quite large in my experience, and having smaller tests for internal methods can help uncover problems without having to break out the debugger and track down an issue somewhere deep inside a request handler
i have a class which is complex enough that just about every single method is tested with a full test class
er, its only half finished....
i have started to feel like unittest expects lots of small classes
i'm using pytest
why use classes at all then? just grouping?
So, grouping
yeah
not a bad idea, never done it like that
i started doing it once I learned you could run tests within files from the commandline
Are there class-scoped fixtures? Is that a thing?
yep!
Oh that's useful
session, package, module, class, function, method iirc
which means its made once for the class
then there's a lot of unittest.mock and unittest.mock.patch stuff going on too
I have a few prs in the works to patch over every method that gets the cwd for anything, and be able to configure everything from the logging and whatnot
i mean uh
- set the configuration to a custom test config, in order to not use the user supplied config when running tests
- clear os.environ and reset it when done with the test suite
- load a test.env rather than the user env
this all ensures that the test suite is disconnected from the current environment
I'm currently patching my plugin system to load plugins from a different folder when running tests, too
ty, I haven't really gotten into advanced pytest setups yet
heh, well it sounds like you're just working on testing complicated things
this is good, I've only ever used it for smaller projects
shouldn't have written such a complicated file in the first place
look, I'll be honest, the reason I've gotten so far into testing is because the code was too complicated to easily refactor.
The code was bad and not easy to expand its feature set, so I have been writing tests to make the refactorings easier ;-;
alas, programming
I mean, tests are good too, but that's what made me do it after saying I would do it
there's a lot to be said for saying you'll write some code and actually writing said code
also a lot to be said for reading docs.... but also having easy to find docs 
like i know there's a module level mark feature in pytest but finding where that is documented is the tough part
sometimes I don't even bother with "user guide" docs and go straight for the api reference
that way you can at least scroll through and look for things with promising names
or you can try to find links to related functions starting from ones that you're familiar with
here tell me how to use this object https://docs.pytest.org/en/6.2.x/reference.html#tmpdir-factory
or if you're lucky, related functionality will be grouped together
(I did figure it out eventually, but....)
and its like a mobius strip...
everything just links to everything else?
that's probably worse than not having docs at all, because now you wasted your time trying to figure it out instead of just reading the source
although I'm sure the source is its own convoluted nightmare
often my most used documentation tool is dir() and inspect.signature()
i wish i was kidding
that's really frustrating
in general I wish it was easier to contribute revisions to documentation
I've gotten in a habit of just, ignoring the documentation at all
yeah, it should be trivially easy for a user to submit an updated description for a function like that
but it isn't
and then I set my PYTHONWARNINGS environment variable to not filter anything so anything that I'm doing that is deprecated or anything I know of
So I’m trying to run some tests on hardware written with circuit Python. Any tips on how to check the functions are working properly if there’s no expected return type?
great.
also I'm aware that I don't need to have lint on all of the different python versions
wdym?
@pearl cliff ... my patch is now causing other problems ...........
please, do yourself a favor and never test
oh my god thats why
....
Argument defaults are created at function definition time.
that is why my patch would not actually work
yes, this is why the mutable default argument trap is a thing
that is also why I appreciate bugbear
IRONICALLY, if it was a mutable argument, this would not have been an issue
because I was patching the variable that sets the default, it was unable to be changed, and was being the old value.
real_answer = 42
def thing(answer: int = real_answer):
return answer
if I import this file and patch real_answer to 69, calling thing without args will still return 42.....
@potent quest dm
...what?
read private messages
no thanks.
oh that's a fun one
solution was to make them None and then if None set x
since I assumed they weren't None in the code already, lol
wtf!!
okay, I have a problem with my test suite and its apparently causing segfaults on the github runners
it doesn't even get to start, it just imports and boom
macos 3.10 only too!
its so weird
I moved a project folder on my PC but tox still thinks it's in the old location. I'm getting py36 run-test: commands[0] | pytest -q Fatal error in launcher: Unable to create process using '"C:\Users\r\Desktop\RunMany\.tox\py36\Scripts\python.EXE" "C:\Users\r\Desktop\GitHub\RunMany\.tox\py36\Scripts\pytest.EXE" -q': The system cannot find the file specified. which makes sense because C:\Users\r\Desktop\RunMany no longer exists, but that's not something I have hardcoded in anywhere. So how I make tox realize the change?
nvm, fixed, just needed to delete .tox folder
How might one interpret a coverage report like this? As far as I can tell, every piece of code is executing?
--------------------------------------------------------------------------
src/evergreen_hq/__init__.py 4 0 0 0 100%
src/evergreen_hq/__main__.py 26 0 6 1 97% 32->23
src/evergreen_hq/intake.py 38 0 6 0 100%
--------------------------------------------------------------------------
TOTAL 68 0 12 1 99%```
The function in question:
"""Run the monitor application.
Params:
forever: If false, breaks after first empty result
"""
redis_stream = RedisStream("evergreen-events")
with console.status("Monitoring event stream..."):
most_recent_id = "0"
while True:
chunk = await redis_stream.read_events(
most_recent_id, 0.001 if not forever else 1
)
if not chunk:
if forever:
continue # pragma: no cover
else:
break
most_recent_id = chunk[-1].msg_id
for event in chunk:
if event.test:
continue
console.print(f"\nNew Event: {event.msg_id}")
console.print(Pretty(event.dict(exclude={"msg_id", "test"})))```
I think it means the if on line 32 that, if true, would go to line 33, is never run (never true)
Oh, I should add Line 32 is for event in chunk
So I suppose I'm receiving a chunk, but on the last iteration there is no event in it.
I read 23 as 33 
23 is the first line within the while True block. I think I'm getting a chunk without any events, so those lose 4 lines don't execute at all on the last iteration
What do the Branch and BrPart columns in the coverage report mean?
Ah that can't be, chunk is just a list so if not chunk should catch the empty list. I can't see any way that the last four lines don't execute if it gets past the if not chunk guard.
I'd guess it's not smart enough to realize the 32->23 situation can't happen 
Well, it forced me to refactor to cleaner code in any case. Removed that guard entirely.
chunk = await redis_stream.read_events(
most_recent_id, 0.001 if not forever else 1
)
for event in chunk:
if event.test: # pragma: no cover
continue
console.print(f"\nNew Event: {event.msg_id}")
console.print(Pretty(event.dict(exclude={"msg_id", "test"})))
most_recent_id = event.msg_id
if not forever: # pragma: no cover
break```
If I have tests in a tests folder, how can I consume modules that are one directory up?
I've tried...
smtpSystem = __import__("../SMTP.py")
import ..SMTP
from ..SMTP import SMTPSystem
among others
One directory up?
Can you show a tree and the error messages you got
You might be missing __init__.py files
Yes.
I didn't add any __init__.py files
The module is just in it's own file
Project/
Tests
test_email.py
main.py
SMTP.py
I'm trying to test the classes in SMTP.py that I'm writing in test_email.py
and I'm using pytest
@placid berry import SMTP
hmmm
But then... Alright. I'm gonna have to ask on the VSCode Discord. For some reason the Python Test plugin stops detecting the tests when I do that
So I can't run them in the test explorer
VSCode Discord.
do you mean https://discord.gg/wwuaZGAP
is there anyone here with some experience with robot?
ah well, parameterized fixture based on the glob of a path... what am i doing lmao
just gotta figure out how to write it
is robot robot on pypi?
!pypi robot
ah, doesn't look like the above then 😛
but my problem is more python related
!pypi robotframework
im running a python script using robot, and that script imports some local python module but its not able to import it
never heard of it
even though it is in the pythonpath
probably best to explain the problem and people will be able to help
what's the project structure?
its very complex but the testcase is quite deep in some folder, then theres the library resource file that is one directory under the root, the testcase imports the resource file, its able to find it, but when executing the resource file, it imports a module that is local to its directory and thats what is failing
failed: ImportError: No module named libraries.utils.runFabric
even though it is in the python path/home/test/akashr/<namehere>/libraries/utils
the resource file is inside libraries but the test that calls it is in some other directory
and this is python2 lol
no idea ¯_(ツ)_/¯
Can you show the tree?
Are you using importlib_resources?
Python 2? Why
You might need from __future__ import absolute_import?
And you might be missing __init__.py files
both "robot" libraries look useful
well nvm the first one looks like a nothing project
but the 2nd one seems worth digging into
yes I figured
Hi guys, needed some help with apis in python, im trying to login to an api and dont have much knowledge about requests and session.I have made a username and password file as constant at the moment.Can anyone suggest me a good resource for this.I plan to take cookie and sessionid from json and pass to an api further
You'll probably want to make a help room as this channel is specifically about unit testing
Maybe #web-development ?
@hexed cloak Thanks
does the working directory get changed? and is the import relying on the current directory?
if you're using pytest there's --import-mode parameter/setting that makes a huge difference to how things get imported . I thinj the default is to always change to the directory containing the test module, which is ptobably not going to work if your test modules are namespaced - --import-mode=append worked better for my project
Not sure how much of that applies to python2
turns out it was because i did not export PYTHONPATH
we're trying to manually run some tests before they can be automated through jenkins and its a mess
Hi! In hypothesis is their a way to generate random length tuples, where each item is a string?
Hello guys,
I've a little prob here with Unittesting.
So I built a Menu function working as following :
def menu(self):
a = input(...)
if .. :
b = input(...)
if .. :
c = input(...)
return a,b,c
I want to make some tests but they didn't work and I don't get why. Here is one of my test :
@patch('builtins.input', side_effects = [1,20,1])
def test_menu_1(self):
self.assertEqual(self.app.menu(), (1,20,1))
Thank you very much for your help !
!pypi pex
tldr input waits for input
!e
this won't what we expect since this isn't connected to a terminal:
input()
@potent quest :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 1, in <module>
003 | EOFError: EOF when reading a line
thats because its "side_effect" not "side_effects"
In [5]: def menu():
...: a = input()
...: b = input()
...: c = input()
...: print(a, b, c)
...:
In [6]: with mock.patch.object(__builtin__, 'input') as mock_input:
...: mock_input.side_effect = [1, 20, 1]
...: menu()
...:
...:
1 20 1
imo it'd be better to use return_value instead of side_effect unless you really need a "side effect" (which in this case i don't think you do)
also a list [1,20,1] is not the same thing as a tuple (1,20,1)
side_effect can do several different things at once, so imo it's clearer (and less error-prone) to use return_value
return value is for single values, side effect lets you do more complex actions
set a mock function etc
and i just showed it as an example, the point remains the same
doesnt matter if i print or return
go ahead try return value, it only works for single returns
In [5]: def menu():
...: a = input()
...: b = input()
...: return a, b
...:
In [6]:
In [6]: with mock.patch.object(__builtin__, 'input') as mock_input:
...: mock_input.return_value = [1, 20, 1]
...: print(menu())
...:
...:
([1, 20, 1], [1, 20, 1])```
obviously not what they are looking for
side effect set to an array iterates through the array for each call
or you can create a mock function that does more complex actions etc with a closure
I- I missed the patch.... my support was the least helpful lol
nit: should use builtins since __builtin__ is a cpython implementation detail
it doesnt work unless you use quotes
Thank you very much for you help ! 😄
Robot Framework
oh, I don't know it 😁
h
is this: == The candidate name to be displayed with a number (1,2,3,4 or 5) beside each name:
THIS?
print('The candidates running for class prefect are:')
candidate_1 =input('1): Shalom ')
candidate_2 =input('2): Henry ')
candidate_3 =input('3): Kneecole')
candidate_4 =input('4): Brownapple')
candidate_5 =input('5): Egg')
OR... THISS:
a= 'Shalom'
b= 'Henry'
c= 'Kneecole'
d= 'Brownapple'
e= 'Egg'
print('the candidates running for class prefect are: ')
print(str(1)+')'+ a)
print(str(2)+')'+ b)
print(str(3)+')'+ c)
print(str(4)+')'+ d)
print(str(5)+')'+ e)
i usually use pytest-cov
def main():
ind = yaml_as_dict("test.yaml") # yaml_as_dict has an open with 'r'
cld = yaml_as_dict("test1.yaml")
print(ind,cld,sep='\n---\n',end='\n\n')
for key in cld.keys():
if key not in ind.keys():
ind[key] = []
try:
value = compare(cld[key],ind[key])
ind[key]+=value
except:
pass
# print(ind,end='\n\n')
write(ind)```
and my test file looks like this
```python
...
data1 = [...] # can be something
data2 = [...] # can be something
data = [data1, data2]
with patch('extract.open', mock_open(read_data=data)) as mock_open_file:
# mock_open_file.return_value.__enter__.side_effect = [str(data[0]),str(data[1])]
extract.main()```
i need `ind` to read `data1` and `cld` to read `data2` while mocking
here i cant assign `read_data` to data cause it is a list. Is there anyway i can do that?
Why not pass them in as arguments to the function?
didnt get you
which function ?
or is there any function for multiple mock open ?
no, i recommend using an ExitStack:
from contextlib import ExitStack
from unittest import TestCase, mock
class TestFoo(TestCase):
def test_foo(self):
with ExitStack() as patches:
mock_thing_1 = patches.enter_context(mock.patch(...))
mock_thing_2 = patches.enter_context(mock.patch(...))
mock_thing_3 = patches.enter_context(mock.patch(...))
...
you can also write a context manager function that uses an exitstack internally and returns a dict or tuple of mocks
those are different things, the above gives a page on the success or fail of the tests, not the coverage of the code that ran.
from contextlib import ExitStack, contextmanager
from unittest import TestCase, mock
@contextmanager
def patches(*args, **kwargs):
with ExitStack() as patches:
mocks_anonymous = tuple(patches.enter_context(patcher) for patcher in args)
mocks_named = {name: patches.enter_context(patcher) for name, patcher in kwargs.items}
yield mocks_anonymous, mocks_named
class TestFoo(TestCase):
def test_foo(self):
with patches(
mock.patch(...),
mock.patch(...),
mock_x=mock.patch(...),
mock_y=mock.patch(...),
):
...
i probably got something subtly wrong, but i have a patches function like this in my actual test suite code at work
huh nice
of course now that multi-line with is allowed, it's less necessary. but still useful if you want to re-use the same patchers over and over
eh, I don't think most ppl are on 3.10 yet
i think it's 3.9 too, no?
no, just 3.10
I just use the black style multiple with
funny thing is pypy just released 3.8 support so you can now try pypy
with mock.patch(
...
) as foo, mock.patch(
...
) as bar, mock.patch(
...
) as baz: ...
I'll let black tidy it up as 3.10/3.9 format as and when it decides to
yep, i have been messing with it a little bit
it's definitely faster in the small toy benchmarks i've tried
things like looping over lines of a file and doing text processing
Best thing is my test suite passes on it
But is it faster at installing packages from pypi.org?
The celery and twisted test suites for pypy take aaaages
haven't tried lol
I use poetry for package management so I don't get to see what packages are built, it hides all of that.
But you can enter multiple context managers on the same line?
sometimes just to see that info I export the requirements from poetry and then install the requirements file with pip
also I was looking at all of the pytest-dev/* repos yesterday
!pip pytest-incremental
that is nice
Oh I misread your message @frigid basalt
Also this code just recreates the deprecated contextlib.nested
unfortunately it's not compatible with pytest-xdist, which is interesting
i didn't know about contextlib.nested - why is it deprecated?
Ffff
I started on 3.7 💀
Feels like my head is full of all this actual garbage knowledge
yall old
I mean, using python for a while*
someone told me about % str formats a few days ago
it's still part of the logger interface (presumably forever)
I don't use that part of logging :P
This is my favourite quote I've ever heard 😆
I get what you mean though, but it's very interesting to me and I learn a lot from you.
anyways back to unittesting...
the reason I was looking through all of the pytest-dev/* repositories is because I was looking for something like pytest-dependency that works with pytest-xdist
it's like
pytest-xdist is great but it sucks how much compatibility it breaks
Eg I can remember stuff getting deprecated, but then never remember if it got removed
for example pytest-incremental
it works great but I wish there was a collection mode where it could run with xdist to collect the completed tests
it structures the imports and what-not to only run the test files that are affected by an edit
!e
import contextlib
@contextlib.contextmanager
def contextlib_nested(*fns):
fn, *rest = fns
with fn() as v:
if rest:
with contextlib_nested(*rest) as vs:
yield (v, *vs)
else:
yield (v, )
with contextlib_nested(
lambda: contextlib.nullcontext(1),
lambda: contextlib.nullcontext(2),
lambda: contextlib.nullcontext(3),
) as v:
print(v)
@hexed cloak :white_check_mark: Your eval job has completed with return code 0.
(1, 2, 3)
how about that?
that fixes the old contextlib.nested problem where the context manager is called too early
shame you can't unpack the as v:
that'd be a really nice feature
wdym "too early"? is that a problem w/ my implementation as well?
Isn't the way xdist works is by using multiple processes?
yeah
Isn't it impossible then to use both?
yeah, pytest-incremental is incompat
however I do think it would be possible to have a data collection mode on pytest-incremental
how xdist works is it runs xx workers, they all collect the tests, and the master process checks they're all the same. then it distributes them to workers by telling each worker which tests to run
I think that incremental would be able to collect the dependencies and success/failure from an xdist run
but not necessarily apply the incremental info
however, with some work it would be possible with xdist IMO
after collection it would skip the tests that it doesn't need to do
sounds simple, should be doable
yeah eg consider with contextlib.nested(open("foo"), open("bar")) as files:
if open("bar") fails but open("foo") already succeeded it won't be closed
This happens to not be a problem with mock.patch because it doesn't do anything until it's entered
ahh i see
yeah in this case it doesn't matter
hence the recursion in your version
doesn't the exit stack also solve the problem?
Ah no, I actually take callables to solve that
oh that's nice too
I use recursion to avoid dealing with type(x).__exit__ and sys.exc_info and __context__ or whatever
Yes as long as you call enter_context immediately after calling each context manager
right
Eg files = [s.enter_context(open(fn) for fn in filenames]
And not
[s.enter_context(f) for fn in filenames for f in (open(fn),)] or something
Wait that ones fine
That one above is odd but it's safe
Here we go this one is unsafe:
files = [open(fn) for fn in filenames]
[s.enter_context(f) for f in files]
There we go
oh that's a good one
wait what
so the built in open method.... it works how?
what does init do vs enter?
afaik __enter__ on a file object doesn't do anything, right?
Some context managers acquire system resources/do mutation in the call/init (and just have a no-op enter method: def __enter__(self): return self) and some do acquisition etc only in the enter
so how is this safe?
That one is not safe
Anyone know any easy way to get docstrings for overloaded functions at runtime?
don't think you can
@typing.overload```
The `@overload` decorator allows describing functions and methods that support multiple different combinations of argument types. A series of `@overload`-decorated definitions must be followed by exactly one non-`@overload`-decorated definition (for the same function/method). The `@overload`-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-`@overload`-decorated definition, while the latter is used at runtime but should be ignored by a type checker. At runtime, calling a `@overload`-decorated function directly will raise [`NotImplementedError`](https://docs.python.org/3/library/exceptions.html#NotImplementedError "NotImplementedError"). An example of overload that gives a more precise type than can be expressed using a union or a type variable:
:/
Anyone available to help with a unit testing question? nobody answered in the help channel
?
Hello...I have some questions about mocking dependencies for unit testing using pytest in Python. Specifically, I would like to mock a dependency imported by a class which has a function I'm going to call...but I'm not sure how to reference the dependency correctly in my patch call
From my understanding I need to specify the path to the file that actually is doing the import...
From ocr_util.py:
from automatedroutersdk.http import get_http_session
Then in my test code:
with patch('automatedroutersdk.http.get_http_session') as mock_get_http_session:
But that doesn't seem to mock it correctly. So I'm assuming I need to also specify the folder path to the file and class which are actually importing this library
Actually at this point I've made a BIT of progress...I'm debugging in to my called code, right past the point where it should've received the mocked object. And it does see it as a generic function now rather than a sessions object that it was before.
ocr_utilities.request_ocr_results(url=mock_results_url, bill_image_key="mock_bill_image_key")
So that code seems to let it find the get_http_session_mock. But that mock itself is supposed to have a get function whose value I want to mock. And setting that up like this hasn't seemed to do anything:
get_mock.return_value = "fjkldjfsld"
http_session_mock = Mock()
http_session_mock.get = lambda x, y : "fjdkfljds"
get_http_session_mock = Mock()
get_http_session_mock.return_value = http_session_mock```
!pypi coverage
Python interface to coveralls.io API
pytest-cov
maybe use vcr instead?
https://github.com/kiwicom/pytest-recording is a nice vcr.py wrapper
Question:
I have a real case scenario. I have an API that works with Chat API (API to use WhatsApp programmatically). I want to write unit tests.
Now, the question is, in regards to the inner philosophy of the design of these tests:
When tests are ran, they send a message and the response is returned. I check that the logic that wraps these API calls works ok. Everytime the tests are ran, a message is delivered to my number in WhatsApp. I REALLY don't mind it, can just archive it and whatever. However, would you, for some design reason, recommend that I instead patch the request to the API?
Thank you very much beforehand :)
Isn't that usually what you do? You patch whatever you're using to make requests as to make it return a pre-determined response (as in whatever dictionary you're supposed to get).
Unless the whole point is to actually test the sending of the bytes.
I assume you're just testing the features of your API?
Hmm, I'm just testing that everything is working properly
I just can't picture other developers getting random messages from tests that they didn't even ran
Maybe I should make it a development env variable?
Thank you very much by the way
Yeah really it's very hard to test something like this, many don't even see the point.
In general though I'd say it's a bad idea, I mean people build clones of APIs they're making wrappers for.
What is "it"? You mean patching?
No, the opposite. Directly using the service in tests is usually a bad idea from what I've heard among others and I think so too.
@lunar hatch what library are you using for tests and for making api requests btw?
If you want to see examples of this, the Python Discord writes tests for their bot. It patches the library it's using so that no requests are going through.
Very simple: unittest, testclient of FastAPI, and the server uses httpx to post to the API
dang it i don't know a patcher for httpx
There must be one, I just took that for granted hahaha
IMO since pydis uses aiohttp rather than patching it themselves i would use aioresponses
!pip aioresponses
Thank you very much for this suggestion :))
so the code to patch httpx can be found in here, but you won't be able to use this package directly, given you're using unittest https://pypi.org/project/pytest-httpx/
Is pytest like a superset of unittest?
it can run unittest tests without any modifications
Meaning: pytest features >= unittest features
Awesome
Just what I'm looking for, thank you very much
Huh, why patch HTTPX rather than just patching the method that calls it?
but you will have to rewrite your unittest tests to not be unitttest tests in order to use pytest specific features
Hm, you made me remember, that was actually my approach in the first place, I didn't even write it but that's what I thought initially vaguely
what do you mean?
In my code I just have one method that does that interactions with HTTPX and the rest use that method.
So when testing code I can just patch that.
unittest.mock.patch decorator
It can be used as context manager, decorator, etc
ah, yeah, I use that to patch all of my other methods so I'm only testing one method at a time
in retrospect I shouldn't do that all the time because integration.... lol
Is it a rule of thumb to always test one thing at a time?
Integration what?
What do you @potent quest think of using it to patch the HTTP request?
response to integration:
i should be testing that the methods work together as well, not just each on their own
Hahaha, I'm confused
Ok, is it a rule of thumb to always test one thing at the time..? I don't get that. BUT, afterwards you say that you.. shouldn't do it because of "integration", integration could mean several things, what is it in this case? Now, I'm doubly confused hahahaha
well, I use aiohttp.get() in whatever functions need to make a request, and I use aioresponses in order to mock out the response rather than unitttest.mock.patch, this gives me a full response object that is made by the library.
Ohhhh, that sounds useful
integration tests. Its where you test everything works great together. EG two methods where one calls the other can work great on their own but for some reason when you put them together you find a bug with the return value of one.
Ohhhh, so that's what you meant
in my case, I've been patching most of my methods and only testing one method at a time but I should also write some integration tests which don't mock out every single other method (slightly exaggerating) in my code and test that they all work together
it is, and much easier to mock by telling aioresponses: return this text with status code 200.
in bluenix's case, it seems like they mock out their own method which calls httpx internally, so they don't need to mock the response at all.
What is your real case reason to not use httpx instead of aiohttp?
underlying library already uses aiohttp & that library needs websocket support
httpx doesn't support websockets
That's exactly what I asked about :) thank you very much!
although I'll be honest I'm inclined to use httpx when I don't need websockets 😛
I've found that it wasn't too bad implementing WebSockets myself really
I use HTTPX for the HTTP/2 support
It also seems to have less issues overall
Hey everyone, I am kind of new to the channel here so I am glad that there is a channel for learning about pytest and/or unit testing more generally. I am trying to build up a habit of integrating unit tests into my coding (self-taught here), but I am struggling with "what" should be covered in the unit test(s). So I have a small snippet of code I was hoping that we could discuss to help me get on the right track with my thinking. I am also working on getting better with adding type hints to my work, so if there's some mistakes and you want to point them out, please let me know.
import sys
from typing import MutableSequence
# Lets add some elements to our container, and every time that we add an alement, we'll
# see how Python allocates memory for our objects we print with sys.getsizeof()
def print_array_size(n: int):
array_based_sequence: MutableSequence = []
for i in range(n):
array_based_sequence.append(i)
print( f"After adding element {i}, the memory allocation of the list is now: {sys.getsizeof(array_based_sequence)} bytes" )
The way I see it, you want to test each behavior that a user relies on.
Here a user expects:
- To be able to pass any integer.
- It to print that many times, with an incrementing count.
If this isn't a library, then just see yourself as the user.
So what you want to do is write a test that gives the function a big integer and maybe a smaller one. Is it supposed to work with negative numbers?
Then have another test case, it will count that the amount of times you print is the same as n, and that each print includes "element {i}".
That's how I would go about it
That's going to be flaky. If you change the way you call httpx or even how you import it, stuff will break.
What I would probably do is:
- separate the logic bits out into unit tests for code that doesn't talk to
httpxin any way - test the HTTP interactions via integration tests
or use a library that will mock httpx's responses 😛
like responses for requests, or aioresponses for aiohttp.ClientSession
oh I should've looked here first
respx is the equal lib for httpx
Asserting what HTTP calls you make is sort of like patting yourself on the back.You don't really know if they're right, because you write the code and you write the tests. So if you misunderstood the API, your tests will be as wrong and your code.
You can also refactor the code to make a slightly different call, for example convert 10 calls into a single batch call, or use some custom caching. Should your test break? Probably not.
i have a few cases where i need the return result, but I'm requesting resources that exist on a server, so its more to test that my code can properly handle a downloaded zip file, without extracting that part that downloads the zip file to another method.
in most cases I'm just using them since they block all requests in order to not touch the apis with my code since I'm lazy
I would extract the download_zip as a parameter and pass a fake one in tests
yes, I should extract that but honestly cba
well, you did decide to write tests 🙂
your solution: extract methods and fake them
my solution: snapshot a few responses from the api and save that, and provide that when testing 
fake, not mock
edited ^_^
well, doesn't really matter
as bad/good as it is i try to write my test suite as dynamic as possible
although for repeatability i should make it slightly more static
What do you mean?
Yes exactly, all requests go through one method which is the only one that directly interfaces with HTTPX and returns the response json deaerialized.
I can just mock those dictionaries
I wouldn't want my tests to break if I change client.get to client.response, or from httpx import AsyncClient to import httpx, or httpx to aiohttp
because it's more or less an implementation detail
But they won't?
eg for that zipfile the test uses a resource directory, zips it, and then passes it to the test
Maybe you didn't meant patch as in patch?
oh wait
I read your original question backwards
sorry
🤦
blue, did you mean that you have a method that calls httpx and you mock the method that calls httpx, not httpx itself?
yes, mocking/patching/faking/stubbing/recording the wrapper method is better
async def request(self, method, route, ...) -> dict:
...
No other code interfaces with HTTPX. So I just override this method in my testing really, as to return pre-determined responses
Then I'll have to write tests to directly test the interface with HTTPX. Haven't gotten to that yet
that makes sense, but i can't always see when that would be useful for a program's internal structure. imo it makes sense to call httpx or aiohttp directly within a method
like, i can't see when i would use one over the other
Using something like this ^ it's somewhat similar yeah.
Hi, I just started learning Python but I wanted to know your opinions, maybe you know more about it.
Hey @toxic pagoda!
It looks like you tried to attach a Python file - please use a code-pasting service such as https://paste.pythondiscord.com
Does anyone know how to put the code here?
You click the link in the bot post above, paste your code into your browser, hit the "save" icon, then copy and paste the new URL
@toxic pagoda ^
Thanks
Okay I think I have a bit better of an understanding here, so we want our unittests to confirm that the behaviour we expect still prevails in the code we have written. Just to extend this one step further, should we also be including tests to examine the wrong inputs, or do we save tips specifically for the expected behaviours of the function?
Personally I don't usually test failures unless that is also expected.
Like the example I gave with negative integers, if that is not allowed then you should have a test asserting that an exception is raised. Since that is expected behaviour.
I truly don't see the point in for example passing a string and asserting that range() raises a TypeError.
Fair enough. I'll just stick with testing for expected behaviors for a while just so I can build some good habits.
Assuming you have type annotations, the type checker will ensure that the correct type is passed
What I like to test is more that the value (for example a certain structure of lists, dicts, tuples, etc.) is correct.
Obviously the code will break if you pass a list where an integer is expected 😅
this is probably the biggest advantage of static type annotations
yes, you do lose some expressiveness due to the limitations of the current system
but you gain a huge amount of test coverage, almost for free, covering test scenarios that you almost would never think to write by hand
One of my coworkers was complaining that a python type annotations weren't useful because there was no compilation step to prevent you from bypassing the type of system, like in typescript
i think they're completely missing the point, unless they want to rewrite our entire application from the bottom up
yes, if you are starting a new web server project at a new company, you would probably be better off with a statically typed language, especially if you have a large number of developers and/or don't trust that your developers know how to write tests
but given that a huge number of applications are already written in python, i feel like rejecting "typed python" is nothing but bad business sense and dogmatism
Hell, you can just ignore that in TypeScript so what's the difference really!
if I patch a module in conftest.py will that ensure that it's patched automatically in all tests (whether I remember to patch it in any future test or not)? I'm feeling a lil paranoid
the goal is not to wake up in a cold sweat with nightmares that I'm calling real methods of this very stateful module when my tests run in CI
it seems the answer is an "autouse fixture" https://docs.pytest.org/en/latest/how-to/fixtures.html#autouse-fixtures-fixtures-you-don-t-have-to-request
tends to be best not to patch stuff in autouse
as it's then spooky action at a distance
instead refactor your code so that state is managed in a dependency you inject into other functions
eg instead of:
from . import stateful
def foo() -> None:
stateful.poke()
...
stateful.poke2()
do:
from . import interfaces
def foo(stateful: interfaces.Stateful) -> None:
stateful.poke()
...
stateful.poke2()
also use pytest-randomly and CI to check to see if your tests are dependent. What's your fear if they do mutate your stateful module?
What's your fear if they do mutate your stateful module?
The module is boto3, so maybe "stateful" isn't the right word. My worry is that someone who has authority to change things in AWS will run tests that change things in AWS
@hexed cloak what do you mean by "action at a distance"?
if you think of "lines of code" as points in space, then if some line of code "far away" from another causes it to change its meaning.. without any "lines of code" connecting them... then you have the physics equivalent of "spooky action at a distance"
compare,
def f(): return 2
def g(): return 3
print(f() * g())
with,
def f_spooky():
globals()['F'] = 2
def g_spooky():
globals()['G'] = 3
f_spooky()
g_spooky()
print(F * G)
don't use globals tho
I'm not intending to be argumentative btw, just want to make sure I grasp the point
to me it seems unintuitive to look at a test that calls a boto3 client method and expect that that test is really going to destroy AWS resources
i dont think anyones talking about resources being destroyed
its about how your code is phrased
Well, I am 😄
it is better to have arguments to functions which can be changed, rather than somehow modifying their behvaviour from the outside
but maybe my anxiety about ensuring that can't happen explains why "action at a distance" is a bad idea though, since the next dev who looks at the tests might panic when they see what looks like a boto3 call that destroys AWS stuff
yeah, well exactly
because they can't see that it's getting patched in conftest
right, ok
I guess maybe the simple answer is "patch it like a normal person, and don't forget to patch it, and move on"
it can be as simple as just taking the library as an argument to the function
def suspicious(boto_library=boto3):
...
yeah I get that, I think I understand the normal way of doing this, I'm just having anxiety about what could happen if I forget to do that at some point
but the conclusion I'm reaching is that "don't forget then" is the best answer
all I have to do is make a fixture and then pass it to every test, and everyone can see what's going on
doesn't boto3 have a client instance?
it does. you create it like ecs_client = boto3.client("ecs")
I use addopts=--block-network with https://pypi.org/project/pytest-recording/
interesting. there's also this https://github.com/miketheman/pytest-socket
then you get: botocore.exceptions.HTTPClientError: An HTTP Client raised an unhandled exception: Network is disabled
I don't actually need to inspect boto3's behavior over the network; I just want to prevent it doing anything outside my local machine at all costs
That's desired
I'm not testing boto3
If/when I'm doing integration tests I'll revisit this
right but it blocks all other network traffic
good
that's on http at least
Sorry?
oh, you mean it blocks HTTP traffic
again, good (imo)
The reason people don't use globals is because of the exact argument that Aporetic is explaining.
It means that finding where something is changed or executed becomes significantly harder.
@app.route('/activity', methods=['GET', 'POST'])
def new_activity():
name = request.form['act']
act = Activity(name=name)
db.session.add(act)
db.session.commit()
return "Added Activity"
How can I unit-test this Flask function using python's unittest module?
it would be nice to start with setting up Test Client
https://flask.palletsprojects.com/en/2.0.x/testing/
plus I would highly recommend using pytest
even flask docs agree with pytest being better
hello, good morning, good evening
im scratching my head about python unit testing coverage report
i started last week writing tests for my project, tests test what they supposed to test
then i wanted to check the coverage of my tests, i installed coverage via pip
coverage html output now marks the part of my init methods red
i googled around, but all i find says "its automatically set by instanciating your class" (https://stackoverflow.com/questions/53950659/pytest-coverage-strange-behaviour-in-init-class-coverage)
from unittest import TestCase
class TestContextAwsRequestId(TestCase):
def test_context_aws_request_id(self):
context = Context_aws_request_id(requestId='FOO-BAR')
self.assertEqual(context.aws_request_id, 'FOO-BAR')
@dataclass
class Context_aws_request_id:
aws_request_id: str
def __init__(self, requestId) -> None:
self.aws_request_id = requestId
how can i make it covered?
Pretty sure @dataclass overwrites __init__
Oh it's not, weird
yeah, it stays red without
other parts of my programm fully unittested also appear as "non hit", unsatisfying experience so far 😦
Are you using pytest-cov? What's your configuration?
no, im using the out of the box unittest + mock
my .coveragerc only defines the folder where the src files are stored
source=src```
tests are a directory higher
i have tests that cover a if/else statement, marked red, but the tests give the expected results and pass (very strict, narrow tests)
coverage version is 6.2
Is it ran in a virtual env?
yes, a venv with python 3.8
And running the command you specified in coverage config did hit all the tests?
all 18 i have, no failures, thats why im scratching my head
adding a dot to a exceptionmessage i covered triggers a fail as expected
but it is covered red
well, then, goodbye, i will have to solve this on my own, thanks for the experience
for anyone still reading and interested
Wrote HTML report to htmlcov/index.html
Name Stmts Miss Cover Missing
------------------------------------------------------------
src/rebuy_dataclasses.py 30 11 63% 32-41, 48
src/rebuy_main.py 25 14 44% 18-53, 61-78, 82
src/rebuy_recommendations.py 36 28 22% 8-12, 17-27, 31-41, 45-52
------------------------------------------------------------
TOTAL 91 53 42%
calling it with unittest is doing the trick
......................
----------------------------------------------------------------------
Ran 22 tests in 0.020s
OK
Wrote HTML report to htmlcov/index.html
Name Stmts Miss Cover Missing
------------------------------------------------------------
src/rebuy_dataclasses.py 30 0 100%
src/rebuy_main.py 25 0 100%
src/rebuy_recommendations.py 36 0 100%
------------------------------------------------------------
TOTAL 91 0 100%
ty, bye bye 👋
Hello, I'm looking for a technique to mock an import so that it never actually imports the original file. If you're familiar with jest in javascript, something like jest.mock('./path-to-module', () => { /* function that returns mock import result */ }). Effectively, I'm trying to not need the module installed at all or have the testing run try to import it (therefore avoiding side effects of importing). I'm using pytest and pytest-mock.
I know how to mocker.patch a method on a module, but I don't know how to mock the import of the module itself so that it never tries to import the original module.
If anyone knows a technique, I'd be very grateful.
Python's import system works using a dictionary called sys.modules
!d importlib
!e ```python
import sys
sys.modules['abc'] = 5
import abc
print(abc)
@frigid basalt :white_check_mark: Your eval job has completed with return code 0.
5
!e
import uuid
listed_accounts = []
class User:
def init(self, username :str, password :str):
super(User, self).init()
self.password = password
self.username = username
self.abort = False
self.id = uuid.uuid4()
self.inf = (self.username, self.password, self.id, self.abort)
if len(password) < 10:
print("Invalid password! Must be at least 10 characters.")
else:
print("CREATED ACCOUNT!")
listed_accounts.append(self.inf)
def delete_account(self):
xchecker = input("Are you sure you want to delete your account? (Y/N): ")
if xchecker "y":
SeLf.AbOrT = tRuE
eLiF xChEcKeR "N":
self.abort = False
def login(self):
xusername = input("Enter username: ")
xpassword = input("Enter password: ")
if xusername sElF.iNf[0] AnD xPaSsWoRd self.inf[1]:
print("Seccesufuly logined in to account %s" % self.username)
mom = User("MOMMY1234","1234567890")
mom.login()
@queen junco :x: Your eval job has completed with return code 1.
001 | File "<string>", line 19
002 | if xchecker "y":
003 | ^^^
004 | SyntaxError: invalid syntax
Do you have a question about testing?
i'm trying to create a DRY factory fixture object in a way that allows me to get a different fixture objects based on the parameters, do anyone know how to do it properly?
@pytest.fixture
def dataframe(request):
file_name = request.param
...
# for single dataframe it works, i'm getting by file_a parameter in the request object as expected
@pytest.mark.parametrize("dataframe", ["file_a"], indirect=True)
def test_it_should_create_valid_dataframe(dataframe):
pass
# don't know how to make it in a way that i can have multiple parameters and get multiple fixtures based on the one dataframe fixture
# first parameter creates my input dataset and the second output dataset
@pytest.mark.parametrize(...)
def test_it_should_create_valid_dataframe(dataframe_file_a, dataframe_file_b):
pass
so i don't want to create explicitly fixtures for dataframe_file_a and dataframe_file_b but utilize the existing dataframe
one solution that i came up with is
def dataframes(request):
for file_name in request.node.get_closest_marker("fixtures").args[0]:
...
@pytest.mark.fixtures(["file_a", "file_b"])
def test_it_should_create_valid_dataframe(dataframes):
dataframe_file_a = dataframes[0]
dataframe_file_b = dataframes[1]
pass
but it feels a bit wrong to use it this way 
how would you want to be able to use it in a test?
you don't just mean having a parameter named dataframe , but dataframe_file_a and dataframe_file_b ?
yea,
@pytest.mark.fixtures(["file_a", "file_b"])
def test_it_should_create_valid_dataframe(dataframe_a, dataframe_b):
pass
I mean, it's almost the same, named parameters access via list/dictionary
how can I implement Validity testing, range testing and unexpected failure testing in pytest? And what is the difference between Validity testing and Expected failure testing
What about something like this, @brittle dove
import pytest
from pandas import DataFrame
import logging
log = logging.getLogger(__name__)
def dataframes(request):
return DataFrame([], columns=["a", "b"])
dataframe_a = pytest.fixture(scope="function", name="dataframe_a")(dataframes)
dataframe_b = pytest.fixture(scope="function", name="dataframe_b")(dataframes)
@pytest.mark.fixtures(["file_a", "file_b"])
def test_it_should_create_valid_dataframe(dataframe_a, dataframe_b):
log.debug(f"{dataframe_a=}")
log.debug(f"{dataframe_b=}")
this will work but requires each time to explicitly define each fixture so it's quite redundant
how many dataframe fixtures do you need?
will probably have +30 
wow, ok :)
I want to write some unit tests for an application that is using spark but the idea is that in the unit tests folder i'll exclude spark as a dependency so only tests with plain old python objects will be involved, would you consider this setup fine with regexp extracted in such a way for tests? it's more an idea as I would need to extract spark / python related code in a similar way.
# compute.py
REGEXP_ID = re.compile(r'\((\d+)\)')
def compute(dataframe: DataFrame):
dataframe\
.transform(some_logic)\
.transform(some_logic2)\
.transform(some_logic3)
def some_logic(dataframe: DataFrame):
return dataframe\
.withColumn("id", F.regexp_extract("foo", REGEXP_ID, 1).cast("int"))\
...
def some_logic2(dataframe: DataFrame):
...
# test_unit.py
from my_module import REGEXP_ID
def test_extract_digits():
assert re.search(REGEXP_ID, 'foo (1234567)').group(1) == '1234567'
i see.. are you using randomly generated data sets?
not in the unit tests, there i'll use some simple handcrafted examples, in my functional tests I have factories where they are generated randomly, in e2e tests they are based on fixtures with sample data from real production data (saved csv)
cool, sounds a bit like hypothesis-based testing
i've noticed a recent hype around that term hypothesis-based testing, wondering what's the difference to regular factories, with factoryboy you could probably build similar scenarios to generate the tests 🤔
good question
can someone explain difference between unexpected failure and expected failure? how can I implement testing for unexpected failure?
Tests failing on an unexpected failure is the default behaviour
xfail is basically a fancy skip - that still runs the test - and it lets you include the exception type - it can help avoid a test bit rotting even while it's failing