#unit-testing
1 messages ยท Page 7 of 1
How? ๐
Agree that using a pattern like that is a good practice in general, wouldn't you need to monkeypatch the repository then?
You would just have a test repository standin
I think you might have misunderstood what I meant. If you would put the entire db query in a plain Python function, that takes data as input, and returns data as output you can quite easily monkey patch it.
I mean, let's imagine it's a function - how would you monkeypatch it?
I don't think that's possible in python, and if it is - I think it's not very practical?
It's in the pytest docs: there is a "builtin" fixture called monkeypatch that will simplify this thing.
I mean, how do you monkeypatch a function?
In general I strongly dislike mocks and monkey patch as its incredibly easy to accidentally create worthless and mislead tests with them
def a():
return "a"
def b():
print(a())
How would I monkeypatch a here?
In your unit test, you could do something like this: monkeypatch.setattr(the_module, "a", lambda *args **kwargs: "hello world")
Well, what if it's used in multiple modules? Would you go monkeypatching everything? 
A lot simpler than implementing a proper repository pattern, even if that is a good practice!
Also if it's imported you'd have to monkeypatch module it is imported in
No, not necessarily.
Repository pattern is simpler since you could just provide a mock implementation instead
Or patch a specific method
To ease monkey patching, Import modules and use module.foo
I mean, that works, but I'm not doing that just to be able to monkeypatch everything ๐
And welcome to one of the reasons why its called "monkey" patching
You would need a repository stub, i.e. more test code. But I don't disagree that it is a good pattern. Monkey patching has it's use cases too, for sure. Very simple and easy to grasp
The person just needed to use a dependency override in fastapi ๐ค
In case of sqlalchemy you can reconfigure a session maker instance for tests too
It's a recommend practice to get helpful test helpers going while it's inexpensive to get them started
Try that, and then compare it with patching one single function afterwards ๐
e.g.
session_factory = async_session_maker()
async def get_db() -> Iterator[AsyncSession]:
async with session_factory() as session:
yield session
session_factory.configure(bind=...)
Or override dependency in fastapi:
app.dependency_overrides[get_db] = new
yield
del app.dependency_overrides[get_db]
It's quite unfortunate the python dependency injection story is so fragmented
Isn't that monkey patching?
Not really?
It overrides a fastapi dependency
I.e. only if you use it like this: Depends(get_db)
It overwrites, not overrides as it looks like.
What would be the difference?
Overwriting is basically monkey patching, as I see it. Overriding is extending an existing behaviour (such as inheritance) and over-riding a default behaviour.
You can do anything you want, really ๐ค e.g. you could use old dependency in your new dependency
I don't understand the distinction though
Yeah, there's a lot of different libraries for automatic di 
Different frameworks try to incroporate DI too but it's usually misused
what's the value in a DI framework? i never really understood that
Usually resolving a hierarchy of dependencies and managing their lifecycles
ahh, i see
Inversion of control and ease of replacement of inner dependencies
in that case, would pytest fixtures be considered a DI framework?
e.g. in case of a typical web app you may need:
session -> RepositoryA,RepositoryB -> Service -> UseCase
Resolving that by hand would get verbose
They're a form of DI
Pytest fixtures are a di framework, unfortunately very organic instead of organized
i've used Depends in fastapi which i know is very much injecting a dependency, but i see it as more of a convenience than something i can fundamentally structure my design around
is this DDD terminology?
Python makes numerous things very easy,so oftentimes by the time you realize you could use an di framework, starting to use one will be unfathomably expensive
I don't know
There's a couple issues with depends:
- Dependencies are closed after the response is sent as of right now
- You obviously can't use it outside of fastapi
- You have to import fastapi into your domain logic, which isn't that good, but it's not that bad either, if you don't want to import it you'd have to wrap all of your classes into functions that would resolve them in fastapi layer
- Basic support something like singletons would be nice too
If you need to support API and something else fastapi's di goes out of the window
You obviously can't use it outside of fastapi
why not?
Because you... can't?
what does "outside fastapi" mean?
https://fastapi.tiangolo.com/tutorial/dependencies/ we're talking about this
Using fastapi's di outside of framework request/response lifecycle/context
you'd have to write your own logic to interpret these Depends annotations if you wanted to use them outside of fastapi
e.g. I have a CLI and want to use depends here
Surely there's a function in fastapi that does the injecting, you can just call that.
have you seen the fastapi source code?
๐
well that's a statement with a lot of implied horror heh
i mean, that's kind of a bold statement to make about any framework
I wish someone would wrap svcs by hynek
what would such a function even look like?
ultimately all Depends does is call a generator function
(or an async generator function)
the framework magic is all doing that within the asgi lifecycle
Dependencies are closed after the response is sent as of right now
@viscid basalt so a more full-featured DI framework might allow me to define various scopes? like a dependency that's scoped to a client's login session?
@pearl cliff For me the best solution is to use fastapi's DI where it makes sense (e.g. getting something from a request, like a header) and using separate DI for everything else:
async def get_user(header: str = ...) -> User:
pass
@get
@inject
async def endpoint(
user: Annotated[User, Depends(get_user)],
service: Annotated[Service, Inject]
) -> ...:
...
I don't think that's possible
"Classic" di implementation defines 3 lifecycles - singleton, scoped and transient
(i'm happy to read about this in a book or whatever if you don't want to explain it all now)
scoped scoped to a di "request" and cached, transient dependency would provide new instance to each object requesting it
i mean, that does sound a lot like what fastapi does
Fastapi only has scoped dependencies
Depends aren't cached though, right?
It is
wat
(In a context of request)
oh
ahhh i see
but surely a transient dependency becomes "scoped" as soon as i pass it somewhere as a function parameter, right?
or is the idea that you don't do that
wouldn't i just want DI at the edges of some sub-unit within my code, and then pass around capability objects or w/e therein?
Let's imagine we have a di framework:
container = Container()
container.add_singleton(Singleton)
container.add_scoped(Scoped)
container.add_transient(lambda: random.random(), float)
Singleton will behave this way:
with container.request() as req:
s1 = req.get(Singleton)
with container.request() as req:
s2 = req.get(Singleton)
s1 is s2 # True
Scoped
with container.request() as req:
s1 = req.get(Scoped)
s1 is req.get(Scoped)
with container.request() as req:
s1 is not req.get(Scoped)
with container.request() as req:
req.get(float) != req.get(float)
That's how lifecycles usually work
In case a transient dependency if for example you have 2 scoped dependencies and they each request a transient one - they'll get different instances
Maybe ๐
unless i'm mistaken, fastapi depends can only be "requested" once, from the top-level route handler fucntion
Yes, but you can have dependencies that have dependencies too
It's certainly a lot easier to understand if there is only one scope
sure. but once you're inside the handler function, whatever dependency you obtained you can pass around as a regular object, as a function parameter, instance attribute, whatever
(kinda like how there's only one scope in python functions, unlike most programming languages)
Yes
You can't do something like
def myfunc(b = Depends(B), a: A):
pass
@get
async def endpoint(a: A = Depends(A)):
b(a=a)
right. are you saying that a more general DI framework would allow that?
Depends on the implementation, but I'd say doing that is generally bad
ah okay, you dislike the thing i was about to say i am having an instinctively negative reaction to ๐
I would use a service locator pattern if you need to provide something after the initial injection
Usually if it's something dynamic
right, in my mind things like fastapi Depends convert dynamic scope to lexical scope
e.g.
storages = {...}
storage_cls = storages[name}
storage = context.get(storage_cls)
didn't know there was a name for that. good to remember
That's a big fat lie
๐ฆ
seems like it's easy to write a rudimentary one
i imagine that doing it well is a big design challenge
It obviously depends on what kind of features you need
i actually have a rough draft library based on https://www.youtube.com/watch?v=RqlnWv6NZos
โ
In this talk, Scott will look at an unusual approach to designing internal interfaces and external APIs โ a "capability-based" approach that takes the Principle Of Least Authority and applies it to software design. When this approach is used, it produces a robust and modular design that captures the domain constraints, resulting in an API that...
which isn't quite the same as DI but i found it very appealing
A todomvc style di is easy, but then come the layers of breaking points as things evolve
i'll probably never finish it because i'm back to doing data science and i definitely don't want to go back to web dev. no need for this stuff in my field now.
Writing a simple DI isn't that bad
I wrote a clone of pytests fixtures DI stuff for hammett.. It wasn't THAT bad
Most likely missing on the details then
import asyncio
import contextlib
from contextlib import aclosing
import httpx
from aioinject import Container, Singleton, Callable
@contextlib.asynccontextmanager
async def httpx_transport() -> httpx.AsyncBaseTransport:
async with httpx.AsyncHTTPTransport() as transport:
yield transport
print(f"{transport=}")
@contextlib.asynccontextmanager
async def github_client(transport: httpx.AsyncBaseTransport) -> httpx.AsyncClient:
async with httpx.AsyncClient(base_url="https://github.com",
transport=transport) as client:
yield client
print(f"{client=}")
class Service:
def __init__(self, client: httpx.AsyncClient):
print(client)
container = Container()
container.register(Singleton(httpx_transport))
container.register(Callable(github_client))
container.register(Callable(Service))
async def main() -> None:
async with aclosing(container):
async with container.context() as ctx:
print(await ctx.resolve(Service))
# scoped dependencies are destroyed (github_client)
# singleton dependencies are destroyed (httpx transport)
if __name__ == "__main__":
asyncio.run(main())
๐ค
Oh sure. But it's big enough to be able to run some real test suites, including handling the django-pytest plugin inside hammett :P
https://github.com/adriangb/di allows for infinite number of scopes iirc
Funnily enough my pretty dumb DI implementation is faster than one used in fastapi or litestar
Me too ๐
I'm out of this
i'm interested in what the more sophisticated DI frameworks would do
maybe this is such an alien concept in python because people don't write python applications big enough to justify complicated DI frameworks?
The devil is always in the details. And sometimes that devil will be quite bad for performance.
I think https://python-dependency-injector.ets-labs.org/ is the most popular one? (but I don't really like it)
I worked for 10 years on a ~300kloc code base
(dry lines)
holy cow that's a lot of abstraction
ok, i think i see what that's doing... this isn't like fastapi, it's making these dependencies available anywhere in the code? container.wire(modules=[__name__])
I don't know - didn't use it in a while
https://python-dependency-injector.ets-labs.org/introduction/di_in_python.html this is doing a good job of justifying it
This page describes a usage of the dependency injection and inversion of control in Python. It contains Python examples that show how to implement dependency injection. It demonstrates a usage of the dependency injection framework Dependency Injector, its container, Factory, Singleton and Configuration providers. The example show how to use Depe...
this example from that doc looks like what i usually write:
import os
class ApiClient:
def __init__(self, api_key: str, timeout: int) -> None:
self.api_key = api_key # <-- dependency is injected
self.timeout = timeout # <-- dependency is injected
class Service:
def __init__(self, api_client: ApiClient) -> None:
self.api_client = api_client # <-- dependency is injected
def main(service: Service) -> None: # <-- dependency is injected
...
if __name__ == "__main__":
main(
service=Service(
api_client=ApiClient(
api_key=os.getenv("API_KEY"),
timeout=int(os.getenv("TIMEOUT")),
),
),
)
I don't really like how configuration is done and the fact that you need to wire everything by hand
container = Container()
container.register(Singleton(httpx_transport))
container.register(Callable(github_client))
container.register(Callable(Service))
Becomes
class Container:
transport = providers.Singleton(httpx_tranpsport)
gh_client = providers.Factory(github_client, transport=transport)
service = providers.Factory(Service, client=gh_client)
and it's a pretty simple case too
I have a container with 156 dependencies at work ๐
you all are working on much bigger applications than i am ๐
156 is not that many, but it's not small either
As of testing I generally just need to override my db session ๐ค
And any other external dependencies I may have, like caching if I use it
not anymore in my case :P I'm at 41k python dry lines. But that's only myself...
Including tests?
do you control this in the DI framework, or something external like docker compose?
actually.. that sounds way too much
well yes of course
honestly this number sounds way too big... I've only been at this for less than 3 years
I have a db hosted on second pc, and locally too (without docker) since almost all projects require a db ๐
But generlaly you just override a connection string in your dependency
This could even be done without DI
As I said - just session_factory.configure(bind=new_url)
I'm at 7k in a pet project ๐
To be honest a lot of these are pydantic models
wth.. iommi is 32k
that's a LOT of tests though
django 294k.. that sounds a lot. I am starting to wonder about this tool I'm using honestly ๐
ooh, hah, I have 10kloc in migrations for my main app
I don't think I can develop without DI at this moment, I need to work on better testing support of my library though, because some kind of dependencies are a bit annoying to work with
How do you test the error message accompanying an exception?
(note: using pytest if that matters at all)
this is correct. The .value part is pretty important. I've written code without it and regretted it.
Pytest allows you to have a "match" argument in "raises". When combined with re.escape, it gives you an ability to check the error exactly.
I use it all the time in "with insert_pytest_raises()" in "better-devtools". It's similar to "insert_assert" from devtools but for exceptions.
I prefer creating custom Exception types ๐ and having no need to test exception msgs. (still never encountered usage case when i need testing msg contained in exception)
def add_torque_spec(self, rpm: int, factor: float):
if rpm < 0:
raise ValueError("rpm cannot be less than 0")
if rpm <= self._last_rpm:
raise ValueError(f"specified rpm ({rpm}) is not strictly greater than last entry ({self._last_rpm})")
^^^ I don't see myself create an exception for every value of rpm that is wrong :p
(although in this case I could do without the first test, admittedly)
^^^ I don't see myself create an exception for every value of rpm that is wrong :p
i actually can.
class LessThanZeroExc(ValueError)
pass
class RPMLessThanLastEntryExc(ValueError)
pass
from . import exc
def add_torque_spec(self, rpm: int, factor: float):
if rpm < 0:
raise exc.LessThanZeroExc("rpm cannot be less than 0")
if rpm <= self._last_rpm:
raise exc.RPMLessThanLastEntryExc(f"specified rpm ({rpm}) is not strictly greater than last entry ({self._last_rpm})")
because it makes typed unit testing without checking strings.
and easy refactoring.
and potentially can be just removing fully string explanations into custom exception init
You can just pass like that and it inherits the constructor of the parent class??
Also I didn't know you could import ., good to know
Err, from . import, I mean
sure.
class MyCustomException(Exception):
pass
that is how i usually create exceptions
for django apis it goes as
class FloweyException(APIException):
pass
class KillSwitchException(FloweyException):
status_code = drf_statuses.HTTP_503_SERVICE_UNAVAILABLE
default_code = "action is temporally down"
sometimes i define actually __init__ for creating more custom msgs in them ๐
it will work if they are in same module, that has __init__.py file in it
and application was launched... with ensured that absolute path of the app starts... before this module (u don't have entrypoint script in this folder/module)
custom_module/
__init__.py
exc.py
app.py
app_module/
__main__.py
entrypoint.py
launching as python3 -m app_module
or as python3 entrypoint.py and etc
then relative import in all other modules (including custom_module) works fine
technically entrypoint can be even in same custom_module though
custom_module/
__init__.py
exc.py
__main__.py
app.py
as long as it was launched as python3 -m custom_module or as python3 -m custom_module.__main__ in a way that ensured root folder of python module paths... is at the parent folder
This is getting a little over my head for the moment, since I'm not at that level yet :p
OK, I am having a look at hamcrest
I find it strange that it uses for instance assert_that(someDict, has_key(someKey)) instead of assertThat(someDict).has_key(someKey))
Oops, too used to assertj
(and Java -- I use camelKey too much)
Speaking of which, how do you test that a dict actually has an existing key without hamcrest?
recommendation as soon as possible just in your code parsing dictionaries into pydantic BaseModel structs
https://docs.pydantic.dev/latest/
they will autovalidate pressence and correct type of all required keys.
Data validation using Python type hints
dictionaries are bad = full of magical keys and values (unless you are able to do strict typing in newest verisons, but even that is not fullproof)
Depends on what you call "newer versions" -- the project I'm on uses 3.11
class YourStruct(BaseModel):
requried_key: int
with pydantic
without strict mypy/pyright, typing is not working. So unless you are strict mypy fan, forget about pure typing approach.
even in strict typing approach though we still go with pydantic to parse third party stuff
use pydantic ๐
it makes Python behaving more like Java ๐ where we again use types defined before code is run, interfaces, generics and etc
yeah it is type checker, turning a bit dynamic typing into more static typing
Eh, I've been given an earful already for code that looks "too much like Java" -- from this discord and from other people working on that project :p
But not having that "safety net" that is compile-time type checking is still making me uncomfortable
I must get used to it...
make safe net present then ๐ i can help with providing configuration
there is no reason to write bad code if u can write quality code
your future you will thank you (in a week, or month, or a year)
I will have to obtain the agreement of other people working on the project -- this is not even mine to start with
aww
I was brought in because of my knowledge of physics, I knew nothing about python when I started not even three weeks ago :p
anyway, just use Pydantic ๐
no point to write too many asserts for a typing problem.
pydantic has runtime validation during its initialization
from pydantic import BaseModel
class YourStruct(BaseModel):
requried_key: int
optional_key: str = "asdf"
def test_data():
YourStruct(**someDict) # will crash if having supplied not specified keys
I have done Java for a double digit number of years now, and while it helps me in some aspects, it does me a disservice in others
I'm like the donkey from Buridan at the moment when it comes to writing python :p
๐ค it is common to get issues with best practices of a newly used language
i tried to write Python way a lot when first got started on Golang ๐
>>> a = 1
>>> b = 1
>>> a is b
True
>>> a = 20000000
>>> b = 20000000
>>> a is b
False
So, python does behave like Java a little in this regard
(but this becomes offtopic for that channel)
Eh, that reminds me when I submitted the code for Java's Path assertions for assertj... I really don't get why hamcrest does not use that syntax
i am not at all a Java expert, but my impression is that it tends to push people towards over-using classes in python, whereas in idiomatic python you might just write functions instead
it can be somewhat liberating in terms of program structure to be able to separate your representation of data from operations on data, reserving classes for the subset of times when you really want both simultaneously
True -- in Java everything has to be encompassed in a class. However Java has primitive types which python does not :p
So, this is a strange dichotomy, really
in python whether something is "primitive" is somewhat of an implementation detail
it's actually kind of a nice characteristic of the language imo
You can still stuff everything into a single class even in Java, but... Uh, no
(from the user perspective, not so great for performance)
Even in Python I won't do that
Well, a single file in python that is
Actually you're limited to 2^31 - 1 chars in a source file in Java
But, uh...
Anyway, what I was talking about is that I was surprised hamcrest chose to assert_that(x, has(y)) instead of assert_that(something).has(y) for instance
That makes the syntax rather awkward to my "trained" assertj mind
Btw with Pytest we just
assert some_key in some_dict
If we would be not knowing about deserializers
Not using Django Rest framework serializers
And not using pydantic to deserialize custom code
We would have resorted to such check
Oh, OK... Indeed, this works:
def test_add_torque_spec_does_what_it_says(self):
rpm: int = 2000
factor: float = 0.3
builder = Engine.Builder()
builder.add_torque_spec(rpm, factor)
victim = builder._torque_specs
assert rpm in victim
assert victim[rpm] == factor
I don't like accessing "instance variables" like that but it works...
ahhh, fluent interfaces. generally not common in python except in ORMs and a closely-related family of libraries for data analysis like spark and polars
Ah yeah, I recall having read that name somewhere...
(fluent interfaces, that is)
actually that particular example i think is really nice and would belong in a python codebase imo
but other cases like FooFactory().set_option("q", 1).build_foo() are not typical, because you can just pass optional keyword args instead
Yes, I've read about those; still not comfortable with them and how they're used
Even with lambdas you can have *args, **kwargs... That is something very new to me. I resent using those for now due to my lack of experience
I have enough trouble already doing "base python"...
fwiw *args, **kwargs is not usually considered good design nowadays, except in specific situations
what do you mean by that? When you need them, they are perfect.
right, when you need them. some libraries use them in ways that make things hard to reason about, like matplotlib (passing kwargs deep deep down) and airflow (almost all classes have init **kwargs)
I mostly write/work with web applications and would avoid using kwargs or dict unpacking in general where other devs would prefer it, e.g.:
def create_something(self, **kwargs) -> Something:
model = Something(**kwargs)
self._session.add(model)
return model
I would usually write
def create_something(self, dto: SomethingCraeteDTO) -> Something:
model = Something(title=dto.title, description=dto.description)
self._session.add(model)
return model
Not only it's more descriptive but is more type safe too, you could do something like Something(**dto) but then it's really not different from the first option
Yea and the swagger generated python libs used to be 100% args kwargs for everything which was maddening. Don't know if it's still that bad.
higher kinded types are missing
def create_something(self, kwargs: Unpack(Initargs(Something)]) -> Something:
...
I'm not sure how I feel about the discussion at hand wrt typing since I come from a very strongly typed language (well, except for primitive types)
But since I do have a lot of experience with Java, if you have questions about how Java does this and that wrt typing, I can try and answer
I'll be as descriptive as possible, and unbiased
That is, if you need my input at all -- I'm anything but an authority on the subject after all
@sick shell if you're currently using the unittest library that comes with Python, you might consider switching to pytest. It is (ironically) a lot more pythonic than unittest
One thing that I like with the **kwargs style (or passing in a dict) is that the create_something function doesn't need to be aware of the details of the passed in data, if it is only passing data on to other functions or classes. Also, the function can be re-used in other scenarios that might not fit that DTO instance. Sometimes, custom built types will lock-in code into one single use case and that could lead to code duplication - or even worse: complex OOP hiearchies of DTOs.
But, in most cases it does need to be aware, kwargs are usually used to "proxy pass" a set of parameters to somewhere else and are mostly used with decorators.
In case of my example I can do create_something(a=42) and code would fail ๐คท
Also why would you assume DTOs would have any inheritance at all
I would say it is common that DTOs inherit from a "base" or even several more generic DTOs ๐
Your example is a function that is specific, yes. But in other cases you might want some flexibility with the input data to be able to reuse functions without forcing everything to be in a specific data format. That's when the "bases" usually enter the scene, you want to reuse a function but the data is only a subset of the original DTO ๐
Hello everyone! I just updated a library I released earlier this year, megamock. It improves the developer experience for using mocks by letting you quickly create spec'ed mocks from references and patch things by passing them in instead of using path strings, among other things.
In addition to updating the library, I've created a custom GPT for assisting you with using the library. The GPT has been coached on how to generate the tests via a step-by-step process and I'm curious if this is helpful for anyone. Creating tests that use mocks isn't a requirement for finding it to be helpful.
The github repo is here, and has everything, including the GPT prompts and data: https://github.com/JamesHutchison/megamock
The custom GPT (ChatGPT+ subscription required): https://chat.openai.com/g/g-DtZiDVQsz-python-megamock-test-generation-assistant
with patch.object(SomeClass, 'method_name') as mock_instance:
do_something()
behold. Part of standard unittest.mock library ๐
Usually it should be just
@dataclasses.dataclass
class MyDTO:
a: int
b: str
...
that is just rude (to my time) to answer with ChatGPT.
!rule 10
Hello peeps!
Is there a way of testing something that has multiple functions (which receive HTML data) without actually having to write test HTML?
It wouldn't be a problem, except it is a plugin architecture thingy, so every time you add a plugin you have to write HTML to test it. Is there a way to automate this somehow?
Which kind of html your functions receive when it is not a test?
From where they get it
And what is nature of the function. What it does to html
Different websites tbh
Each function is a handler for one website
Like, I know that it seems daunting considering that, but I also know that some bs4 magic exists that at least makes it easier to do so
The functions just scrape data tbh
For stuff like that I write tests
if html file is present in test_data folder
Data = read from file
Else:
Data = Do request
And save data to file
RunTestedFunction(data)
On first run u get and save real data u reuse then for tests.
Any moment u can delete saved cache to regenerate it
There is even library for this to automate such stuff a bit more (caching requests for tests)
That is a good idea
Just have to make sure to add the downloaded HTMLs to gitignore lmao, for copyright reasons lmao
I git commit them for the purpose of runing in CI and predictability in general for tests
It is your choice though.
Do you know what it is called ๐
I mean that's true, but I don't necessarily think it's a good idea copyright-wise lmao
https://github.com/uber/cassette
Found ๐
Oh, thank
Hopefully these "Uber" people or whatever make trustworthy libraries
Never heard of em
As an option u can encrypt with something simple and decrypt back for usage
Don't use it. Deprecated in 2015 year
Looks like modern analog ๐
Would you look at that
Seems like one of the websites I scrape is currently broken lmao
I would have benefitted greatly from vcrpy now lol
hey guys, how do i get code coverage to work in pycharm community edition? i'm using the coverage library, and upon running python -m coverage run --source= test/ -m unittest discover -s test/ where test/ is the directory for my tests, it tells me Can't find '__main__' module in 'test/'
also is this the correct place to ask or should i ask in #tools-and-devops
Do the tests run without coverage? python -m unittest discover -s test/ ?
no, it runs 0 tests, even though i have 7 defined in test/class_test.py
rn, i am manually using the pycharm run button to run them
but it doesn't throw an error
ohhh, am i meant to make my tests in a unittest class....
unittest requires classes, yes. You can switch to pytest if you want to use functions. But I'm concerned that the behavior is different with coverage and without. They should be the same.
i changed it to be in the unittest class, and now it seems to work when i run python -m coverage run test/class_test.py
however, it doesnt run when i do python -m coverage run --source= test -m unittest discover -s test
oh... is there anything i should check
i think the issue here was
what happens if you use python -m unittest discover -s test ?
that i added a space n --source= test
oh! right
removing the space it runs 0 tests
but with python -m coverage run test/class_test.py it runs 4
it runs 0 tests
your file should be named test/test_class.py
I agree, but often (too often) I see code like class MyDTO(BaseDTO)
Even the wording DTO is not very Pythonesque, sounds more like C# or even old school str myString = new String();
like all design patterns, it's a useful idiom but maybe not worth explicitly building your software around it
how do i get ready for test
What sort of test?
For college
Hi Python testers! I wanted to share a new project that might be useful for you. I write a lot of python command line tools and usually use the Click framework which provides an excellent CliRunner test helper to test the command line script. Sometimes I don't use Click (when I don't want an extra dependency) and use argparse instead. In those cases, I really missed being able to use CliRunner so I ported the Click CliRunner to work with argparse (or manual sys.argv parsing) apps: https://github.com/RhetTbull/clirunner
This is a channel about software testing
Oh I thought it meant unit test
unit testing is a common term for software testing yes
Ok sorry I'm still new lol
Np
Hi guys, a few days ago I wrote a message in #web-development regarding my new drf-api-action project
https://github.com/Ori-Roza/drf-api-action
I struggled to make it understandable for developers and I thought it might be helpful to ask for your opinion.
@proud nebula helped me to figure that my package is great for testing Django Rest Framework web servers by treating REST methods like regular functions.
for example:
"""python
class DummyView(APIRestMixin, ModelViewSet):
queryset = DummyModel.objects.all()
serializer_class = DummySerializer
@action_api(detail=True, methods=["get"], serializer_class=DummySerializer)
def dummy(self, request, **kwargs):
serializer = self.get_serializer(instance=self.get_object())
return Response(data=serializer.data, status=status.HTTP_200_OK)
def test_dummy():
api = DummyView()
result = api.dummy(pk=1)
assert result['dummy_int'] == 1
"""
so first, I want to say thanks to this amazing community, and I'll be more than happy to invite you to use this package let me know what you think ๐
I made an game of Leap Frog for no real reason, but it seems to be running slow. Does the IF statement slow loops down that much?
print('Welcome to your eternal punishment! Lets play some leapfrog!')
jumper_1 = input("Who's the first to jump?\n")
jumper_2 = input("Who will be getting jumped over\n")
y = 0
z = 0
while y == 0:
if z == 0:
print(f'{jumper_1} jumped over {jumper_2}!')
z += 1
print(f'then {jumper_2} jumped over {jumper_1}!')
print(f'then {jumper_1} jumped over {jumper_2}!')
print() will be millions of times slower than if.
what do you mean?
I think I was very clear?
you may have been, but i'm very dumb
You asked if if is slow. In code that does a whole lot of print. Print is millions of times slower. So the question seems silly. Like asking how expensive a glass of water is when faced with an empty bank account, while at the same time buying multiple Porches.
oh i thought you were saying that theres better ways to print with 'if' statements, rather than using only print() statements
The code as given should be so fast that humans should be unable to perceive slowness for a wide range of inputs,could you elaborate on what's slow
how can I use fixture to create a mock file of certain size?
I'm doing something like this
def test_collection_size(create_fake_file):
files = [create_fake_file]
size = get_collection_size(files)
assert size == 32
create_fake_file fixture should return a mock file of size 32 bytes
it's hard to know how to help. where is the full code? What is going wrong?
def get_collection_size(file_list: list[Union[os.PathLike, str]]) -> int:
"""
Calculates the cumulative size of the files in the provided list.
Args:
file_list (List[Union[os.PathLike, str]]): A list of file paths.
Returns:
int: The cumulative size of the files in bytes.
"""
total_size = 0
for file_path in file_list:
if file_path:
try:
file_size = os.path.getsize(file_path)
total_size += file_size
except OSError:
pass # Ignore invalid file paths or inaccessible files
return total_size
@pytest.fixture
def fake_file_content():
# Returns 32 bytes of space
return b" " * 32
@pytest.fixture
def create_fake_file(fake_file_content):
def _create_fake_file(file_path):
# Use unittest.mock.mock_open to create a mock file object
mock_file = Mock(spec=open, read=Mock(return_value=fake_file_content))
# Use unittest.mock.patch to replace the built-in open function with the mock_file
with patch("builtins.open", mock_open(read_data=mock_file.read)):
# Write the fake content to the specified file path
with open(file_path, "wb") as file:
file.write(fake_file_content)
return _create_fake_file
I'm getting E TypeError: stat: path should be string, bytes, os.PathLike or integer, not function
the create_fake_file fixture produces a function. You aren't calling the function.
@silk crescent but i also wonder how this is meant to work: you are patching open with a function that doesn't make real files, then using os.path.getsize on the result.
I'm trying to create a mock file which will return a file object so that I can get the size of the file
isn't this possible ?
First, i would recommend not mocking. Why do you need to mock out the file system?
should I create a temporary file get the size & delete it ?
I have to test if the function is getting the size of a file correctly
sure, why not?
great thanks
1 more thing where should I put the delete the file ? after the assert ?
with another fixture ?
oh no if I make it a fixture then It will be called first before the assert
pytest has built-in fixtures to help with this: https://docs.pytest.org/en/7.1.x/how-to/tmp_path.html
thanks
I got is not a normalized and relative path
from pathlib import Path
PROJECT_PATH = Path(__file__).parent
DATA_FOLDER = PROJECT_PATH / "test_files"
@pytest.fixture(scope="session")
def create_fake_file(tmp_path_factory):
# Create a temporary file in the tmp_path directory
temp_file = tmp_path_factory.mktemp(DATA_FOLDER) / "temp_file.txt"
# Write 32 bytes of data to the file
temp_file.write_bytes(b"a" * 32)
return temp_file
the directory already exists. is that the problem ?
ok I changed it to temp_file = tmp_path_factory.mktemp("temp") / "temp_file.txt" then It worked
You can delete it after you yield in your fixture
Do you really need it scope session?
how do I test a package that makes request.get calls but i want to just use a file that contains some small sample of data from the response? i dont even know how to google for this
it is called patching and mocking. (and the 3d case is actually called using a Spy, although often called Mocking too)
- U can utilize answer above requiring extra third party lib. (global affecting way + extra lib)
- Or u can just use from standard lib mocks and patches https://docs.python.org/3/library/unittest.mock.html , for patching specific lib or class or function (this choice will work with pretty much no code changes, we abuse here python flexibility. U will preferably need to move your code at least into separate method that returns simple values though)
with patch.object(SomeClass, 'class_method', return_value="insert return body of your request.get from file here"):
SomeClass.class_method(3)
mock_method.assert_called_with(3)
- Or u can just rearchitect your code to be accepting via compsition some kind of more abstract
requesterthat can be replaced during testing with loading from local file thing (this choice requires code restructure to more unit testable code architecture)
P.S. last two choices do not require extra libs and not creating extra overhead for maintenance if u need it just once. Consider adding library only if u are really going to use it a lot.
P.P.S. choice #3 is more preferable if u are strict typing with mypy/pyright
i would have used as a semi lazy choice at least 2nd preferably probably.
hello need a bit of help with pytests
i want to use pytest to verify this ValueError is being raised
but how can i pass in input to pytest.raises
if anyone has an answer please pm me because i doubt ill see the message after 30 minutes or so
You have a problem here
How do you differentiate between player 1 and 2 missing?
If you don't care however, I found this link which is very useful: https://jaketrent.com/post/verify-error-message-pytest/
In your case you won't need the assertion, only the with, but here goes
You mean this?
with pytest.raises(ValueError):
...
Probably how to make the calls to input return under test
So I think you'll need to mock out input
Yeah I did this then passed the function but it doesn't do anything
It doesn't matter its pretty rudimentary code for a task I just wanted to see how to test the input can be tested
How do I mock input is it by using exc_info? Or is there an easier way
Show the code for your test so far?
Give me a sec I'll be home in a bit can I pm you?
Best keep the messages in the chat
If you have a long thing to paste you can use
!paste
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 Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.
Fyi, unless you make input a overridable argument to your function, it's going to be a hell to test the details
I'm sorry could you elaborate more on this I'm absolutely new to python and almost have 0 clue on what u just said
The only parameter I want for the input is that it exists whether its numbers or strings
def get_names(input=input):
Then you can pass in custom input functions for automated Tests
But it May be better ux to make a function that handles one player name correctly
It's a pain to have to re-enter the correct name again if the second one is broken
Mocking input is fine here imho
OK, I have a class with a values instance variable which is normally a deque; I want to check whether its .appendleft() method has been called, using pytest
I know how do do this using python-mockito: you would when(instance.values).appendleft(...) and that would automatically mock the function to "do nothing", but what is the equivalent using pytest? I can't really make it out just by reading the docs...
Also, what I really want afterwards is to check whether the function has been called
Uuuh... E AttributeError: 'collections.deque' object attribute 'appendleft' is read-only
So you can actually make that?
I'm more than confused now
Well, I used mockito's .spy() instead and it works
And, uh, no it doesn't
OK, I'm in trouble here
Can you just check where the value ended up?
Eeh... That's a good question :-(
I'll pastebin
I can't see your imports
because any further implications either gives me an OSerror or a TypeError
Don't screenshot code use https://paste.pythondiscord.com/
!paste
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 Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.
Sorry I don't know mockito
You don't need def main and if __name__=="__main__": in tests only executable modules
Ok so what happens when you run the test?
well yeah this is for cs50p and so thats why i need to verify the valueerror personally i wouldnt bother because it reprompts if no input and to me that works
I don't know cs50p but I'd test every branch of my codebase
What happens when you run the test?
I believe however that you can see the intent of the test... How would you do that with pytest instead? The documentation is really not clear :/
Show the full traceback?
its the harvard introduction to python its pretty basic and rudimentary but its a start...i mean so far my program/script works but i have no way to prove that it does and they require you to use pytests to prove it
Sounds sensible
Perfect thanks for the traceback. It's good practise to show your code and full traceback first thing when asking for help
It looks like you need to patch scrabble.input
So wrap your test in with mock.patch("scrabble.input") as mock_input:
so i put that line of code under the test_get_names() and it should work?
Put it where you think makes most sense and see what happens
You'll also need to import mock
With from unittest import mock
sigh Even with pytest-mock I cannot make it work
You can use plain unittest.mock
What happens now when you run pytest?
OK, I don't get it, I'm going to post to the help channel, this is getting over my head
I've tried everything I can think of, nothing works
I'm rather distressed at the moment; I've spent a full hour trying to debug why that test did not work the way I intend it to... mockito, pytest, unittest, all failures
im getting NameError mock is not defined
okay so i installed mock library and imported it and its passing the test but im not sure exactly how or what is it testing
the code now
the traceback
You don't need to install mock it comes with python now
It used to not that's why you can still install it
You can see what's being tested if you use coverage
pytest-cov is a good option
OK, I made it work
sigh
def test_add_updates_deque(self):
sample = 1.0
mean_value = MeanValue()
values = mock(deque)
when(values).appendleft(sample)
mean_value.values = values
mean_value.add(sample)
verify(values, times = 1).appendleft(sample)
I thought I could spy() over the values member of the created MeanValue instance but no
I HAVE reached a middle ground
code
tester
@hexed cloak is this valid or am i wasting time and bad ux by making the ValueError raise an exception?
mocking deque seems like a very odd thing to do. Why not make a deque and check its state?
I would write an example, but I don't understand what that test does. Does this actually call appendleft? when(values).appendleft(sample)
That's an oddity of python mockito's syntax here, and I suggested to the author that there should be a .thenDoNothing() method; what this syntax does is basically, well, make the method pass. In Java, you would for instance write (using the "original" mockito) doNothing().when(theObject).theMethod()
but why mock it at all? It's a data structure you can just use.
I want to test that MeanValue instances do what is required
right, that they append to the deque. You can check that the deque has the contents you expect.
I could do that, yes, but then, when you start empty, you have no way to tell whether the method called was append() or appendleft()
By testing this way I am sure of what is being called
why do you care which it called?
the important thing is that the deque is in the right state. You're tying yourself to implementation details.
Because this is a FIFO queue
ok, so it needs to have the right contents. You don't care how they got that way.
you will have another test that adds two values, and you can see that they are in the right places.
What I care about is that the oldest added value gets ejected when there's no room for it anymore
ok, then test that. don't check the methods that were called.
And .appendleft() does that naturally for me
write a test that adds too many, and see which are left.
you are testing the implementation. you can test just the behavior.
I agree, however testing that part of the implementation guarantees that the behaviour is what I want; I don't even need to test for what happens when too many elements are fed in
When using it I won't care
sorry, you won't care about what?
About the implementation details; the behaviour is documented, and known to work, that is all that matters
@sacred depot so I understand, what does this line do? when(values).appendleft(sample) It calls appendleft or it doesn't? If it doesn't, what does it do?
You can read this as when(values).appendleft(sample).thenDoNothing(), which is more explicit; and it does what it reads like; "when you call the appendleft method of values with exactly what sample... Well... is (therefore, object identity; anything else will not match, then do nothing -- but do record, as a side effect, that this method was called with this very argument"
ok, so it doesn't call appendleft. Would the test still work if you removed that line?
No; you need to tell what you expect
what would happen without that line?
This:
> self.values.appendleft(value)
E AttributeError: 'Dummy' has no attribute 'appendleft' configured
i see.
Python's mockito differs from Java's in that sense
In Java you would doNothing().when(theObject.theMethod(...))
you mean in how you say to do nothing. Both would complain if an un-configured method was called?
No, in Java you work with a mocked object which is fully defined, methods, prototypes and all; which brings in limitations of course (you cannot mock classes which are declared final for instance -- except if you use PowerMock which I avoid whenever possible)
But more often than not I mock interfaces, so this is not really a problem
I rarely "monkeypatch" real object instances
how does the mock object get the full interface?
which means to be brief: you cannot mock a non existing method, that's a compile time error
Reflection :) THE can of worms which you try and never use unless you really have to :)
Basically, if you have a Class<?> object, you can access all the methods in that object
Which is why you declare for instance that you want a final Foo foo = mock(Foo.class) <-- here, Foo.class is a Class<Foo> object (and, also, I use mock() directly here because I declared import static blablabla.mockito.mock, I don't remember the exact path, my IDE does that for me)
You can also mock() "real" instances (as long as the class is not final) but I try and avoid that whenever I can
I already said that about final, didn't I? In fact you cannot even mock(Foo.class) if Foo is final for that matter
raise TooMuchJavaError() :p
it's clear we have different approaches to testing ๐
Which means we can learn from one another ;)
And I love that kind of interaction
(well, that is, if you learn anything from me)
Just to add to what I said, because I believe this is important: interfaces in Java are also Class<?> objects
Which is why you can mock() an interface -- the preferred way of mocking, really
I'm familiar with Java (at least as of a few decades ago)
What I wanted to do with my test however was to spy values; but no cigar, I could not do it
And I don't understand why :/
Also, I wonder about the interaction of hamcrest with other testing frameworks such as unittest, pytest and python-mockito
Argument matchers are fascinating
Not to be overused, but when you need them, there is just no replacement
looks like hamcrest fits well with unittest. not sure about pytest
i guess there's no reason it wouldn't work, it's just philosophically a different direction.
pytest uses the python assert statement for assertions. unittest and hamcrest use assertion functions.
But you can use hamcrest or other assertion functions in pytest if you want.
Ah, yeah
In fact hamcrest reminds me of assertj somewhat but... Well... I believe assertj is more powerful :p
In fact, and I will have to look that up, I wonder how python handles polymorphism
But that will be for later
sigh I hate being rate limited... I cannot include the full code into a post in the help channel :(
There is no unit testing tag in https://discord.com/channels/267624335836053506/1035199133436354600 :(
Does anything like this #esoteric-python message exist? (obviously in a significantly less jank format)
You should just raise the exception you need to raise don't raise one to catch it then raise a different one
can someonw tell me where did i go wrong https://paste.pythondiscord.com/ESIQ
You dumped a ton of code but didn't ask a question
Try python -m pip install instead.
Whatโs a way to have a unit test catch when a class definition is updated but the serialization method hasnโt been?
This just happened, which made a bug because when the data was deserialized back into the program, a bunch of essential data was missing causing the program to misbehave
By โserializaitin method hasnโt beenโ I mean that thereโs basically a โto_dictโ method that was not updated to reflect the new class members
My concern is that if I put a unit test and test for the serialzed string matching, then it will pass unless the test itself is updated which puts me back into the same boat because if I forget to update the dict method I sure as hell will forget to update the test
How complex is the serialization? Can you just reimplement a simpler version of it in the test, run both, compare the two?
I would first try to change the code so it doesn't misbehave but crash hard. If you don't have this you are in any case doomed.
Not sure I understand exactly what you mean here
So it doesn't crash hard, it just doesn't function properly. Basically what I'm saying is that I have a to_dict() method which takes and converts (serializes) the object into JSON, which is required because the objects aren't automatically JSON serializable out of the box. So, if I add another member or otherwise change that class, and I forget to also add the new member to the to_dict() method, then there is silent missing data from the JSON, and then that messes up the program when the data is deserialized on the next run, because there is missing data. Does that make sense? So my issue is that if I were to make a test for this, that test cannot have future modifications in it, which means that the same issue is present because if I or anyone else forgets to add the new member to to_dict(), then same could happen if we dont add it to the test.
One way to test serialization is to find some tests that use one of these objects, and add a line near the top: obj = deserialize(serialize(obj)), and see if the tests still pass.
Would this only catch issues where the serialize method is different from the deserialize one?
Is there a way to compare the to_dict() method with some class metadata directly?
I understand what your code does. I'm saying that your code is wrong. On some very fundamental level. Missing data during deserialization should be a hard fail of deserialization. Not a bunch of missing attributes/keys or something. You always write code so it fails when assumptions aren't met.
After this fundamental flaw is fixed, THEN you fix the problem of testing the serializer for fields missing. Maybe just by changing the serializer to enumerate ALL fields and if a field is neither in a exclude or include list it fails.
I see... So I need to find away to enumerate the class attributes for this
I misunderstood your initial message and got it the other way around @proud nebula
Ah.
Yea. What are we talking about here? Just a random class? Pydantic? Dataclass? Django model?
It would catch errors like forgetting to update the serializers for a new attribute. The test wouldn't have the new attribute on the object.
just a POCO. I wrote the to_dict() method myself and it basically just returns a dictionary, I just had to implement some code for example because the class has attributes which are lists of instances of other classes I wrote, so in there I run [class_b.to_dict() for class_b in self.class_b_list] and stuff like that.
The flaw here might be that my to_dict() relies on me manually updating it.
I wonder if I could use self.__dict__ instead, but not sure how it would handle that case above with the list of other class
File "c:\Users\RED\OneDrive - SORA\Desktop\Flight management\modules.py", line 2, in <module>
import mysql.connector
ModuleNotFoundError: No module named 'mysql'
PS C:\Users\RED\OneDrive - SORA\Desktop\Flight management>
this is the error
i tried reinstalling mysql
Build with Visual Studio Code, anywhere, anytime, entirely in your browser.
Currently, my test job in github actions looks like this:
jobs:
Tests:
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11"]
poetry-version: ["1.2.2"]
os: [ubuntu-latest, macos-latest, windows-latest]
pydantic-version: [1, 2]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install poetry
uses: abatilo/actions-poetry@v2
with:
poetry-version: ${{ matrix.poetry-version }}
- name: Install dependencies
run: poetry add "pydantic@^${{ matrix.pydantic-version }}.0.0" && poetry install --all-extras
- name: Test
run: make test
- name: Upload coverage
uses: codecov/codecov-action@v3
So I test on three operating systems, two versions of pydantic, and two versions of Python. However, this produces 12 jobs total. Each job installs its own poetry, packages, etc. What optimizations would you recommend here?
Well, you can't cache the packages since they may be specific to the OS or Python version.
So I'm not sure if there is anything to optimise here
Sorry, I mean you can cache them. But you cannot share the cache between jobs
Have a look at the "cache" action
I feel like it could be solved with tox. Maybe it has the ability to share portions of packages between python versions or something.
do you need to test with both versions of pydantic? Is this a library you're building? BTW: I wouldn't put the poetry version in the matrix, only things that you need multiple versions of.
I'm also curious what actions-poetry does beyond pip install poetry
I do need to test with both versions of pydantic because I support both of them and they are vastly different in some important parts of the functionality that I touch. Thanks for the tip about the poetry version!
Is this a library you're building?
I have built a pretty great API versioning framework that we already actively use at my work. It's pretty amazing and complex but solves a lot of tough problems. Right now I'm planning to publish an article about it and try to expose it to wider audiences which is why I want to support both pydantic versions.
https://github.com/zmievsa/cadwyn The link if you are interested
U could ensure some sort of caching if u wish
Yes, I understand. That's why I am asking for ideas here :)
Please, read my message. These jobs all have no dependencies. Outside of pydantic 1/2, all of them are very different.
Difficult a bit to cache, since your libraries secondary deps could be updated
Essentially u have no option to cache without having loss of Ci quality
Hmm
That's precisely what I'm asking, yes: whether I can cache something without significantly losing in quality.
As an option I can see only running CI fully for single set of vars.
Cache for other cases
So not running the jobs at all?
I have three platforms and two python versions. What do you propose to cache?
Pip installed dependencies
Based on key out of platform name + python version + pydantic version
Not really important speed up though
It is not like it takes too much time to install it
May be just don't optimize ๐
This will yield the same number of jobs and we will still install packages 12 times.
And what would be the problem in it?
12 jobs take a lot of time and can drain my free CI minutes.
Don't run them all the time. Run tests for single set of variables all the time then
Run all set of variables for releases only
(Github repo release is valid CI trigger)
I appreciate the attempt but you are trying to explain the very basics. I understand this. I also have read the docu and I know which triggers github actions have. Now I am hoping to receive guidance from testing experts such as @river pilot and @proud nebula who might have other ideas and tools in their mind that could help me here.
how can we run multiple python version tests like we run in github ci/cd but locally ?
not like than act
you need multiple versions installed somehow (e.g. using Pyenv or Docker images). from there, you can use Tox or Nox, which are specifically meant for this. the project management tool / build backend Hatch also supports it. but it also would be relatively straightforward to write a shell script for this, or even a Python script.
for hatch how can we switch the version without pruning the existing env first
you don't, you use a matrix environment instead: https://hatch.pypa.io/latest/environment/#matrix
Modern, extensible Python project management
can we do something in poetry as well?
I have multiple python installed & can use nox or tox ?
i haven't used poetry in several years, so i wouldn't know. you'd have to browse or search their documentation. but i know several people here do use poetry so maybe someone can attest.
testing with multiple python versions is specifically one of the main reasons that tox exists, and nox is specifically meant to be a tox alternative with a different kind of interface. you'd have to check their documentation for usage instructions.
great thanks
what's the difference between them ?
other than the fact that nox usese a .py file as config ?
i haven't used nox, so as far as i know that's the main difference. i think the idea is that it allows you to customize the configuration more easily if needed, allowing nox itself to be simpler
are they able to install dependencies from pyproject.toml ?
you'd have to check their documentation, i don't use them, so i don't know what they recommend. maybe someone else here knows and can comment on it.
afaik you can run arbitrary commands
I was seeing nox documentation & saw something like first install dependency then run it. So if I use poetry or pdm I have run pdm install first then run the tests ?
1 thing related to setting up pipelines in a project. I have some integration tests which takes hours to run should I run them in github actions ?
or just run the unit tests
I would try to speed that up first.
have to wait for the server to respond
Hours in computer time is crazy.
it spins up some docker container & copies the ethereum blockchain to setup some mock transactions so it's pretty time consuming
yah there are like 200+ tests
1 way would be to cache the result of the first test which will reduce down the time to 1-2 mins
so the data looks like this
{
"BEE_POSTAGE": "061dfc1fc656410f1901e06f5b413039a6923e2747ca7d8cfe23391cd7b86c20",
"BEE_PEER_POSTAGE": "e032d8ddc7227d0d6c4d0f87db16027924216afd0c00012884ba7af835b4a7c7"
}
for each new node the data changes.these are valid for 1 node & for the tests I need only 1 node so have to cache them somehow. can we do that using fixtures ?
I did something like this
@pytest.fixture
def read_local_bee_peer_stamp() -> str:
with open(BEE_DATA_FILE) as f:
stamp = json.loads(f.read())
if stamp["BEE_PEER_POSTAGE"]:
return stamp["BEE_PEER_POSTAGE"]
return False
then calling it in
@pytest.fixture
def get_peer_debug_postage(printer, read_local_bee_peer_stamp, bee_peer_debug_ky_options) -> BatchId:
stamp: BatchId
if read_local_bee_peer_stamp:
return read_local_bee_peer_stamp
but for some reason they don't seem to return the data from the stamp file
idk know why
Your first fixture is marked as returning a str but you have a path that returns False. If you returned False from it your second fixture will return None.
Is that what is happening?
I'm using the caching mechanism of pytest seems to be working fine
!rule 6 , stop cross posting and advertising ๐
Sorry!
are there any good books/articles/etc that talk about strategies for testing complicated control flow and/or a large number of possible valid states?
i find myself needing to do this a lot, either adding tests to untested legacy code, or testing performance-sensitive code that's difficult to refactor, especially with numpy/pandas/polars operations that tend to benefit from doing more things at once.
i like to think i have a fair amount of experience with it by now, but i also feel like it's the hardest programming-related thing i have to do on a regular basis. so i think it would be useful to see how other people approach this task.
i suppose the best way to test something like a state machine is to test every possible transition separately. but sometimes even enumerating all those possible transitions can be tricky
I'm trying to make temp files using fixtures like this
@pytest.fixture(scope="session")
def create_blank_temp_files(tmp_path_factory):
# Create a temporary directory
temp_dir = tmp_path_factory.mktemp("temp")
# Create 2-3 temporary files in the temporary directory
temp_files = [temp_dir / f"temp_file_{i}.txt" for i in range(2, 5)]
return temp_files
but Pathlib.is_file() is returning False
You know those are just paths right? Not files, or dirs.
isn't pytest creates temp files for the current run ?
I'm iterating the file list
the list of path objects
& then for each file I'm doing is_file()
Your fixture is called create_blank_temp_files which it doesn't do. return temp_files is a lie
then ? how can I make a list of test files ?
Your question is "how can I create a file?"?
Nope as you said return temp_files is a lie then how can I return list[Path]
It's a lie because it's a list of paths. To files that don't exist.
def _make_filepath(file: Union[os.PathLike, str, Path]) -> str:
"""
Extracts the filename from the provided file path.
Args:
file (Union[os.PathLike, str, Path]): The file path.
Returns:
str: The extracted filename.
"""
if isinstance(file, str):
file = Path(file)
if file.is_file():
return file.name
msg = f"Invalid file path: {file}"
raise TypeError(msg)
for file_path in file_list:
if file_path:
filename = _make_filepath(file_path)
I'm doing this
yea, that creates a path. There is no file on disk.
Think of it like this. If I make up a name like "John Andersson", an entire human being doesn't pop into existance. Just because there's a name, doesn't mean there's a person. Same with files and file NAMES.
You have created file NAMES. But there is no FILE.
ahhh understood. is there a way to make temp files in pytest ?
The question is incorrect. It's not about "in pytest", it's about "in python". So if you just search about how to create a file in python, you should find the answer.
Hey, between unittest and pytest, which is considered โbest practicesโ?
both are acceptable. pytest has a lot more features; unittest tends to require a lot more work to achieve what pytest can achieve with only a little bit of effort. but unittest is part of the standard library and pytest is not.
pytest can run all unittest tests ๐
Also, for best practices read
it takes theory of testing
- getting to know manipulating code architecture
in order to understand best practices
technology itself is not able to be best practices, people are able to screw up any framework equally
I'm trying to mock a mysql.connector interface and running into an issue. I'm using MagickMock and patch, and on the one hand, I can tell those are actually working. However, when I assert_called_once on the mock object, the test fails.
My debugging shows that it is, in fact, being called. Not sure what I'm missing here.
@mock.patch('my_module.mysql.connector.connect')
def test_fetch_user_sms(self, mock_db_connect):
sms = '+1234567890'
mock_cursor = mock.MagicMock(name='mock_cursor')
mock_cursor.fetchOne.return_value = (sms,)
mock_db = mock.MagicMock(name='mock_db')
mock_db.cursor.return_value = mock_cursor
mock_db_connect.return_value = mock_db
email = 'john.doe@example.com'
result = my_module.fetch_user_sms(email)
mock_db.cursor.assert_called_once()
mock_cursor.execute.assert_called_once_with('''
SELECT phone
FROM account
WHERE email = %(email)s
AND phone_is_valid
''', {
'email': email,
})
self.assertEqual(result, sms)
i think u a missing not to mock db.
docker-compose up mysql with forwarded ports and u get clean mysql with necessary version for local test executions
we can arrange it as full docker run command if desired
mocking db is rather dangerous practice of having a lot of unecessary testing code. dereasing testing code quality.
u can mock in a good way, with mocking data (pydantic) structures received from another module. that is a right way
I'm well versed with docker, just need to get an export of the prod db structure (not my DB, external service's DB who apparently can't be bothered to give the needed encrypted SMSes over their REST API)
so their solution was to give a Read Only replica DB o.O
u aren't supposed to need having prod db data for that.
your service is supposed to be having in its repository database migrating files ๐
And I wish that rainwater were beer, too
This is an external service, as in, system we integrate with, not even ours. I'm not remotely close to calling those shots for them ๐
well, even if you don't have db structure, lets at least imagine u have.
Write some imagined db migrations sufficient for testing then, fix to right code later then
yep, all I really need is a table named "account", with columns named "phone" and "email"
yup. so, write migration that makes it for you ๐
or at least a basic testing framework fixture that brings it
I was trying to use Mock for this, to learn Mock, but you are right, it's probably the wrong situation to use it in
Thanks! Also, love the Darkwing duck reference ๐ big fan, hits right in the childhood
Hey people. I am struggling with something for a couple of days now. Can you take a look? It's an inheritance issue:https://stackoverflow.com/questions/77684533/how-can-i-modify-the-python-unittest-setupclass-method-of-a-child-class-without
I mean... that all sounds very wrong on many levels...
You probably need to describe what you're actually trying to do, instead of your idea of a solution.
xy problem...
Sure. Did you read the description? I can elaborate on the parts that you think are not clear.
Yea, you're avoiding to describe the real situation though.
You've abstracted it so much, so we have no idea if your idea of a solution is crazy or smart.
Alright. I'll try to explain step by step. Please let me know which parts are too abstract.
I am writing some unit tests for a function of a module. This function needs to be tested against multiple input sources. So, I thought I could create one test class (the parent class), and then inherit the test cases from there for every other test class that will be used to provide different input sources.
The test methods are only 3 but I want to create 3 more classes that will run the exact same test, only with different class properties
Sounds like you should either use a parametrized test in pytest, or just write some functions.
The class properties are defined in my parent class in the setUpClass method. In every other child class, I want to overide the class properties with the NEW class properties, because the tests are written in a way to receive the class properties as input
I cannot use other libraries than unittest. I need to find a way to do this here.
I have to use unittest because it's the module used by my company for a testing framework that is built for multiple teams.
You should try to fix that heh. But yea, not right now.
So, back to the problem.. Why does the child's setUpClass overide the parent's setUpClass? Why isn't it executed lineraly? Start with class 1, set it up, run the tests, go on to the next, etc.
You want to run some code, but sometimes you need some input to be X, sometimes Y. This sounds like you want just some functions.
that's not what happening... but in any case, this is just a bad idea
I ran the snippet I sent with a debugger, and when the interpreter reaches the first test case, the class properties are modified according to the child's setUpClass method ๐ฆ . If this is not what's happening, can you explain how it works?
Yes, that's what happening, because you're writing the property ON THE CLASS. Which is a very bad idea. And it's a very bad idea to inherit test classes.
Again: WHY? You haven't answered this. What's wrong with reusing the code with just some plain old functions?
I don't want to repeat the code in every class. Do you mean calling other functions than the setUpClass method?
No I mean... you say you want to resuse code. The way to reuse code is to write functions. Like when you first learned programming.
Could you explain with an example how I could re-use the tests written once multiple times in Unittest? I am not sure if I am following.
I don't think you should reuse the tests. I think you should write functions.
u could be using pytest. it is more powerful tool with having concept of fixtures that can allow configuring any intriciate setUps for tests.
i would say though that changes properties like that does not look like a good design to me though.
def test_x():
a()
b()
c()
d(1)
assert something
def test_7():
a()
b()
c()
d(2)
assert something
is better as
def foo(x):
a()
b()
c()
d(x)
def test_x():
foo(1)
assert something
def test_7():
foo(2)
assert something
It sounds to me like you are stuck in a mental track of thinking of it as "reusing tests" but you could instead think "a test is just normal python" and then make functions
looks good enough to me ๐ in this way pretty much going with go
you don't have to bring up go every sentence you know
๐ค in python it can be Fixture Or Function, depending on the need
Pytest Fixtures are a bit more preferable over functions, due to them being more explicitely..... testing code
and having control how much they should be reused per test. (saving some performance from recreating them)
You're distracting from the problem again Darkwind
There were some solutions that proposed to create another class with all the tests and inherit that instead but it seems that it creates the same issues. Simple writting a function doesn't seem like a good option for what I need to do. Thanks anyway.
You've still not shown any code that describes what you're trying to do... so it's really hard to say anything else.
You get the help you enable. You haven't let us help so ๐คทโโ๏ธ
But I've shared the stackoverflow url. There is a snippet there that describes a very simple example.
I really ain't doing something more complicated than that.. I need to make sure that the property defined in the parent class won't get modified by the children's setUpClass method before the test runs for the parent class first.
that's it
I'm also pretty sad about Darkwind's answers. He writes too much which distracts everyone from the problem completely yet he doesn't help beyond the most basic problems. And the more advanced ones get overlooked because of his replies ;(
No, that describes your attempts to implement your idea of a solution. It doesn't describe the real situation. It's a classic xy problem. You are attached to your idea of a solution and won't even discuss the actual problem.
No, it's not. That's you being mentally stuck because you've made up your mind about the direction you are going.
quick question if I had a function(A) and every other function(B,C,E,F) uses it, do I really need to do testing on A?
def A(num, foo=1):
return (num*2)+foo
def B(num):
return A(num, foo=2)
def C(num):
return A(num, foo=3)
...
No, you only need to test the function B,C,E,F.
thanks, just checking
You're welcome.
need maybe not. SHOULD? Probably yes. Because you don't want test failures on B if A is broken. That's just annoying as hell, since you think B is broken, but it's actually A.
yeah, it could be. but that only if B contain more code other than A(...), right? but B only has one expr and its just A(...)
sorry for the poor English
ah... yea ok, then I guess it doesn't matter a lot. Although that seems like a very rare situation.
yeah its rare that why I'm asking
I feel the opposite would be justified. Test A extensively because it holds the actually implementation. And then minimally for the rest for coverage.
than I would need to list of all the possible foos values, than loop over
Probably not. You just need to handle boundary conditions where behavior changes.
You can use property based testing to find them... but honestly I think mutation testing is easier and faster.
this example is a bit misleading, without context of what you minify from its very hrd to give a correct answer
I am pretty sure the example mirrors my problem as the foo is size of the data that I want to read from a stream and num is the stream itself
you turned a file reading example into a math example
also wat does the size repressent?
size repressent foo
i mean is it a magic number, a size of a data field, something dynamic - the names you gave stuff make it a drunk guessing game, and i do'nt play those
I am sorry for not making it clear. what about I give you the project idea?
a rough outline may help understanding a bit
function A repressent read_ctype function which take ctype and bytes converting it to a ctype/python-type value and return, and functions(B, C, D, etc) the others are just read_int, read_char, so on, the differents between those functions are just one variable which at the end would be an int(the sizeof the ctype)
saving data as bytes in python without dumping python object using pickle
sounds like the struct module
than I don't need to worry about the reading/writing part I, only the file management part. thanks
whats the final goal for your libray there - it sounds like you have something large in mind but dont yet have the needed skills for a number of layers of that tool
I do have the skill, I just don't have enough motivation to do it
you where trying to implement a alternative to struct in a possibly ineffective way - thats a key indicator of knowledge gat in combination with research gap - thats a skill issue
and it wasnt the end goal (which you left out)
oh, now I get what you mean, but thanks
now - whats the actual goal you have with the software, it may easily be possible that there are numerous libraries that get you 80% of the way with much higher performance/reliability than something fresh homegrown
(a key mistake all of us to way too often is reinventing wheels, but wobbly)
I actually love to reinvent the wheel, the point is simply to gain experience
what I'm saying wheel come in colors and shapes, the best is out there but sometimes you want to learn how they work
yes, but you dont need to make the universe for each apple pie you want to make
its easy to make load of wobbly ruins when ignoring preexisting tools too much - its always a question of what you you want to get done
aka a wheel collection is not of help if a complete waggon is needed
Definitely. I would need to go now, to finish this project
What if A is a private interface? I wouldn't want to test my implementation details.
does anyone know how to test a function which executes sql queries
an example will be appreciated
I don't really buy that dogma. If it's code that you need to make sure it behaves a certain way: test it. Private or not, I don't see how that is relevant.
With a test db?
Sounds like a dangerous approach in the wrong hands. I have seen people make their projects incredibly hard to change by testing too much of the private interface.
I mean, I agree that when you are the only developer โ you can do whatever fits. But if you have middle and especially junior devs around you โ dogmas like that one can save the project. Or do you have an alternative way of keeping the fragility of the tests low?
You can test "public" interfaces badly. I don't think blanket rules like that are very helpful. It depends too much on the specific details.
Only testing the public surface in a web app would lead to you doing all tests with selenium. That's madness. So clearly that thinking can't be taken to the extreme.
You can, yes. But you gotta somehow teach less experienced programmers to test well so having blanket rules does not feel too bad.
It's like "having more coverage is generally better than having less coverage".
How do you make sure that the quality of tests is high even when you are not looking? :)
If it communicates via API and the API is public, then there is no issue.
If it doesn't, then yeah: testing only via public interface would be tough.
"Not looking" seems like the problem :)
More mob programming with the juniors is a good idea.
Let's say there are 4 teams of 4-6 backend developers within the company, 30% of developers write really poor tests and 50% of developers write more or less ok tests but with a large number of issues that could be corrected with a good review.
How would you review everyone in the company? :)
And that's a "good situation" example. Most teams I worked at do not write tests at all or write completely useless tests that barely check anything and never really run.
So many mistakes you have to make prior to that situation. Don't let it get that bad.
What can I do to prevent it? Or what can I do to start making it better?
Prevent it is fairly straightforward: good onboarding where you do pair/mob programming to establish strong culture.
Fixing it is worse. Much much worse. Especially if recruiting outpaces your ability to get people behind your idea.
Recruiting definitely outpaces us in that regard :(
Huh, I guess our onboarding is a lot less involved than what you recommend. We just help with tasks if there are issues, do one-to-ones, and do regular review.
The problem is: many developers who conduct onboarding also do not know how to write high-quality tests. This had caused big issues in the past too ;(
if management doesn't raise standards, find a job where management sets a higher standard
Sometimes you can raise the bar and mgmt will follow. I did that at my previous job.
Or try to creep in higher standards on your own ๐
this is a recipe for burnout and stress in my experience
unless you can explicitly get management to agree with scheduling in time to add tests to legacy code, and add tests for new code, you're going to be putting in extra work for no benefit to yourself
Agreed. Tried to do this on my current workplace. It worked +- but with insane investments from my side.
and it will be trying to drain the ocean, if it's you vs 4 other people doing the opposite, you can't win
i tried and made progress but never really succeeded, leadership didn't want to change the culture
Doesn't work too. The people who work on adding these tests are just doing them for coverage and now you have a bunch of tests that are not really testing anything (or even worse: that only test deep implementation details without actually testing the functionality)
Ergh, leadership closes eyes on my experiments and at least allows them to go. For projects/repositories where my code is main one, they silently agreed to have those standards at least
yeah but how does that work on a schedule?
when i develop a feature i usually end up spending longer testing it than developing it
maybe it's a domain thing
for data science code you can spend two hours knocking out a working implementation, but then figuring out good tests will take you the rest of the day
Shrugs. I think I operate faster it at least of equal spending time here.
I am used to my style of doing things, and doing in any other ways will slow me down
(Not developing from unit tests first, or not going with static typing shenanigans)
Hehe, made rapidly new tool demanded with coding back and front in my favorite golang. Tool received approvals as thing that was needed and received backlog of new features demands.
Thankfully nobody minded that I once again creeped in Golang as main language.
It really fitted tool requirements though. Internal tools in WASM in one go lang for front and back are just awesome ๐
Really easy to extend in features and maintain now
Wow. Seems like your leadership is in for a wild ride when you leave
This sounds like a one-man show where you do not manage others and do not worry about others.
When you work like this โ anything goes. The problems start occurring when you have dozens of other developers to worry about.
Or the opposite. My repositories are the only ones which have maintained documentation and very througly self documented
Good docs do not solve the problem of the developer bringing more new technologies than the company could handle :)
It doesn't matter how well you document your code if the company doesn't have experts in these technologies to replace you with.
๐ that is one of golang beauties. It does not require a ton of new tech libraries to function.
Language alone is having in its std libs all the stuff to solve most of challenges
- Language is very slowly changing in general. Small in syntax sugar and kind of very stable
No matter how good or simple the technology is: bringing it in when there is no one besides you who is capable to support it is a recipe for disaster
There should be a really good reason to use golang and wasm if they were not used in the company before.
Feels like resume-driven development
Well, golang is extremely popular in regards of most dev fun language to learn.
Technically we can expect increases of people knowing it
Especially in our DevOps department, since it is one of most recommended langs for DevOps
At least it brings fun and comfort to maintain it on your own for the next five years.
It is really enjoyable to enjoy your own work and making stuff in quality u can be proud of
It is, no doubt.
Kind of increases dev retention too. That is one of reasons that me deciding to stay for far more amount of years in a company.
No point to leave place u enjoy to work in
Besides golang, I am the one that brings static types with mypy to our python code bases ๐
Made really easy to document code and extend in new features. Or solving some problems.
When your code is quickly reaarangable in its code architecture like kaleidoscope, that is not an issue to bring any requested changes in a quick time
Not always I have chance to work in typed code bases though, but we have ownership rules, the one that coded it is main maintainer. So, I do enjoy work with code my past me made in some previous years. Than more I am in the company, then more I stumble upon my own code to work with once again, which I carefully static typed crafted for future me ๐
That's great! Same here from my side but I use pyright.
I prefer pyright in environments where people are new to typing because of its amazing inference.
Agreed completely. 100% branch cov with high quality tests + 100% typed code do wonders for refactoring capabilities.
Exactly. Who are you, and where did u get the previous Ovsyanka ^_^ ๐
Changing culture is possible. You just loudly proclaim the values you have and follow them and then if that ends up better for everyone people will notice.
At my previous job people still say stuff like "do the right thing, wait to get fired", or "the only way is forward", or "it's the little things", and other battle cries I said over and over.
if one doesnt die by 1000 papercuts there will still be 999 scars
Haha. I like that!
w
What happened to scar 1000๐ค
I assume that the death would happen directly after cut 1000, so in the case of survival the reference point would still be directly after, and thus cut 1000 would not have had enough time to heal/scar.
That part of the joke intentionally is like a requirement straight from a intoxicated po
[0, 1000)
How to detect a popup in Selenium IDE?
Not selenium web driver, but the manual step recording one
I tried it to catch with assert alert, but was unable
Attach the local file to asset83 itโll compile all its data and restarts it
Is there something like a pytest plugin that will let me choose specific tests by number? I have ~1300 tests and want to run subsets of them to find some mysterious interactions.
as a thing i can offer
that's similar, but not what I need
if u want specific tests subset shortcut to run, how about just adding temporally @pytest.mark.mysubset to those specific tests
pytest -m mysubset
Are you lucky enough that the interaction happens if you run the offending test, then many unrelated, then the test that changes due to the offending test?
Or in other words, can you do binary search?
I think I wrote a throwaway plugin for that once. Ultimately ending in my blog series :)
what I ended up doing: collect all the tests to get 1368 node name, put them in a file. Write picklines.py to use random.sample on the lines in the file with a given seed. Run the test suite with the test nodes chosen by picklines. The 183rd run gave me 20 tests that together showed the behavior. Then I could whittle it down to three specific tests that show the bad behavior. That's as far as I've gotten. Now to debug into those tests to understand the interactions.
Crazy but cool :D
i'm sure the seeded random selection could be a pytest plugin, and probably already is...
I would love to hear what the problem was when you nail it down.
if history is any guide, i will not find the actual problem.
but this is very very esoteric stuff that I have done to myself.... so i deserve it.
That's a depressing history. I fought damn hard at my previous job to find the four nasty cases I detail on my blog. One of them I don't know how to protect against systematically but the others I implement as soon as I suspect them even the slightest. 2/3 implemented ~3 years in at my current job :)
coverage.py is very complicated. TBD whether it's too complicated. Measuring itself is extra extra complicated.
@proud nebula coverage.py has a check that the trace function is still correct at the end, to warn people who might have called sys.settrace() in their own program that the data could be wrong (because coverage was prevented from collecting some of it). This debugging session convinced me that I was setting off that alarm when coverage measures itself, and that I don't need to be alarmed about that, so I've quieted it.
The hack I made for randomly selecting 20 tests to run: that seems like something that could be a pytest plugin, but searching isn't finding it for me. Anyone know of something like that?
It's not exactly the same, but I did find this which has more links https://github.com/mrbean-bremen/pytest-find-dependencies
It looks like this one does shuffle and bisect https://github.com/asottile/detect-test-pollution
thanks, someone on mastodon created this: https://github.com/alexwlchan/til/blob/main/python/Run a randomly selected subset of tests with pytest.md the harder part is actually packaging it as a third-party plugin. I might do that.
i just learnt what this means ffs
I am making an app for mobile which detects when I am connected to a certain bluetooth device and executes further code but I am not able to find a bluetooth library
if I use pybluez2 I get this error
AttributeError: module 'socket' has no attribute 'BTPROTO_RFCOMM'```
on this basic code ```py
import bluetooth
nearby_devices = bluetooth.discover_devices(lookup_names=True)
print("Found {} devices.".format(len(nearby_devices)))
for addr, name in nearby_devices:
print(" {} - {}".format(addr, name))```
can anyone suggest me a better library or guide me on what I am doing wrong?
Probably check which version of python has socket.BTPROTO_REFCOM
import os
import random
import string
import time
c = random.choice(string.ascii_lowercase)
print("random lowercase letter. dont fail.")
userin = input("your guess: ")
print("It was: " + c)
if userin != (c):
print("You got it wrong. Say goodbye")
time.sleep(3)
os.system('shutdown -s -t 0')
I can't seem to get this to work
can someone help
Ask something specific Before asking for help, try to make the smallest example you can of the problem. Donโt just show us your entire code base. If you donโt understand the advice given, say so!. Donโt just ignore it. Donโt tell us error messages in your own words. Copy paste them. In full. โDoesnโt workโ is not an error message. How does it no...
can someone help data = res.read()
print(sss)
url = "."
value1=response.json().get(token)```
^^^^^^^^^^^^^
the error is
Copy paste the error IN FULL
Exception has occurred: NameError
name 'response' is not defined
File "C:\Users__\Desktop\test.py", line 31, in <module>
value1=response.data().get(token)
^^^^^^^^
NameError: name 'response' is not defined
done
There is no variable called response.
Exception has occurred: AttributeError
'bytes' object has no attribute 'json'
File "C:\Users..\Desktop\test.py", line 31, in <module>
value1=data.json().get(token)
^^^^^^^^^
AttributeError: 'bytes' object has no attribute 'json'
k now how about this one
.
The error is quite clear.
wait i just add this and it fixed ty for ur help
response = self.session.post(url, json=data, headers=headers
hbt this?
response = data(json=data)
Exception has occurred: TypeError
'bytes' object is not callable
File "C:\Users\HP\Desktop\test.py", line 26, in <module>
response = data(json=data)
^^^^^^^^^^^^^^^
TypeError: 'bytes' object is not callable
data = res.read()
response = data(json=data)
sss = data.decode("utf-8")
print(sss)
url = ""
value1=response.json().get(token)```
@proud nebula
You should move to one of the help channels. This is not the right channel for this.
then where is the right channel
.
https://discord.com/channels/267624335836053506/704250143020417084
And please stop that annoying extra ping.
If anyone is interested in cucumber/gherkin, (Sorry if this is off-topic)
After a few years of being the lone Python fanboy in the OpenCucumber community, I'm starting to see Python get some traction, including an ambitious effort to bring pytest-bdd up to the latest spec.
If anyone here is interested in finding out more, LMK.
I never understood BDD. All the implementations I saw was basically putting regex between stake holders and code, obfuscating for developers and stake holders alike.
Yes, I agree, you never understood BDD.
... that part about regex was fixed a few years ago.
Good to hear!
Hmm. And yet the readme for pytest-bdd has regexes and string matching.
Yes, so my post refers to the effort to bring pytest-bdd up tio the current version of the cucumber language, which has something called cucumber expressions.
https://github.com/cucumber/cucumber-expressions
and a number of other cool improvements.
TLDR: I came here to find out if anyone was interested in helping to fix some of the annoyances like the one you mentioned.
https://pytest-bdd-ng.readthedocs.io/en/default/ for the time being.
Hm. Well ok maybe slightly better. But it doesn't at all take away from my basic point that you're just adding string matching/parsing between some document and the real test code. Especially in Python where code is readable this seems ill conceived.
Yes, except when working with stakeholders who don't read code.
Also, having a spec under version control that is independent of the source is really handy when you change implementations (eg. go from a monorepo in Java to multiple services in Python)
BTW, I don't havee a strong opinion on this, I would be super interested in seeing examples of better approaches.
I mean.. the code is the only truth anyway. The spec file is just fake?
The spec is not fake if it is bound to entrypoints in the code
Just like docutils
It is what makes Python the superior language IMHO, the ability to link across various levels of abstractions.
i wasnt aware of pytest-bdd-ng it looks like fork
I am trying to determine if I am taking the wrong approach on testing a Class that is used for grabbing a Oauth Token from Azure AD (for example). In the class, we use the httpx library to post and return a token. I want to test this behavior. Typically, I would think to use pytest-mock, pytest-httpx to modify the httpx response, however, when I did that it still went to the url used for the Oauth endpoint. So, clearly I did not do something correctly. TLDR: any advice on either decoupling or handling HTTP request objects for unit testing? Any example would be greatly appreciated as well.
if you tried a mocking framework and it didn't work, it's possible that you just made a mistake, no? i wouldn't jump quickly to the conclusion that a tool simply doesn't work. maybe try sharing your test code.
!paste
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 Paste! button in the bottom left, or by pressing CTRL + S. After doing that, you will be navigated to the new paste's page. Copy the URL and post it here so others can see it.
did say the tool didn't work? "clearly I did not do something correctly" is what he wrote
maybe i misunderstood, but it sounds like they were ready to give up on the tool and seeking more general advice
my advice is: figure out the tool first, because "mock the API endpoint with a mocking library that's specifically designed to work with your HTTP client" sounds like a reasonable approach
Sure.. but not blaming the tool.
Personally I would always recommend avoiding mocks as a first idea.
that too, there's a lot to be said there. for example you can construct the request data and make assertions that the request data was constructed correctly
Not because I don't know how to use them, but because it's just fiddly and often done in better ways.
the mocking would only be for an integration test to make sure you glued your individual units together
but yea, you need to show some code for anyone to have any advice
so maybe another piece of general advice is that, if your test looks like this (hypothetical code, fixtures, app, etc):
from myapp.client import login
def test_login(mock_auth_fixture. tmpdir_fixture):
username = "saltrock"
expected_token = "asdfjkl"
token_file = tmpdir_fixture.fspath / ".token"
def _resp(username):
if username != "saltrock":
return 401, None
else:
return 200, expected_token
mock_auth_fixture.set_handler(_resp)
login(username=username, token_file=token_file)
actual_token = token_file.read_text()
assert actual_token == expected_token
you can probably break up your code into testable "before" and "after" functionality that does not require i/o or mocking to test. the test above isn't particularly useful as a test of app functionality. it's primarily an extra line of defense against really catastrophic mistakes in your code. so it's not necessarily bad to have them, but you might find that maintaining the fixtures and set infrastructure is more effort than the test is worth.
@crimson meadow and @proud nebula thanks for taking the time to review: here is a code block. I believe I am mocking the 'wrong' object and I am not sure what I need to mock in my example to have the mock work probably, again a me problem not a tool problem. https://paste.pythondiscord.com/53OQ
Yeah I would agree that it is not useful. And I am currently trying to add support for network proxies via passed in at the cli as by default requests and httpx will use the defined standard HTTPS_PROXY by default. And wanted to have some test to sanity check me as I go through besides just continuously running my own requests over and over. It maybe that this is not the correct way to think about it and I need spend more time on useful tests instead of tests I think will help but just improve 'coverage'.
Understood, as a "sanity check" it's reasonable. I'll review your code when I have a chance later to see if there's a solution for your issue
Hi! We use unittest from stdlib in my work to write all unit tests. I'd like to start using pytest because I think it has some significant advantages (better reporting, lots of useful plugins, more pythonic API, ...). I've already used in in some of my private projects and I believe there's a reason why it's such widely adopted. However, I'm having a hard time selling it to my colleagues, because of the auto-magical fixture system. It's not clear where the fixture comes from and one doesn't get a benefit of typing (which is closely related to editor auto-complete support). Do you have any suggestions how to make use of pytest easier? Auto-complete for fixtures is probably a must (explicitly typing each fixture in test definition is an option, but we're still missing the check of the actual fixture type matching the test header type). Also, any good arguments that the auto-magical fixture discovery is worth it for the other benefits are appreciated.
Pycharm handles the fixtures very well...
Thanks, but it would have to be editor agnostic, preferably LSP-based solution. Most of us use Vim or Neovim, nobody uses PyCharm.
You should try pycharm. It has vi bindings :)
Well, even if I was willing to, our entire team certainly wouldn't. I don't have anything against PyCharm, I just think that ability to use pytest effectively shouldn't depend on any particular editor. Especially since the time we have language servers.
@steel compass you are right that fixtures can be confusing because they are outside normal Python semantics. You might approach the problem with documentation. I find that the set of fixtures doesn't get that large, and is specific to the domain.
The first issue i see is that it doesn't look like you're using the httpx mocker you mentioned
wait... you're using requests?
that's a completely separate library from httpx
not sure if that's the source of the confusion
in this case however it looks like you can just patch out auth.py.requests.post with a function that returns whatever you want
another option is something like VCR, to make real requests on first run, and then return saved responses on subsequent runs
!pypi vcrpy
if you actually decide to start using httpx instead of requests, it looks like pytest-httpx has good documentation for getting started https://pypi.org/project/pytest-httpx/
yeah a bit convoluted at the moment...transitioning to httpx library from requests
another mocking strategy is to actually start an HTTP server in a background thread that responds to certain requests with predefined responses, and either configuring or patching the in-app URL to point to the test server during the test execution
that's a fairly involved setup but it theoretically allows you to transition from one http library to another
Hi all, I'm a rookie developer, and I'd like to test my project that uses Django REST. Any ideas on what I can test for, and how this could be useful in making better software?
if you already have a working app with no tests, you have what's known as "legacy code" and might want to start with the "characterization testing" technique https://www.youtube.com/watch?v=cjxXv0eifhY
You've been bitten by the testing bug, are thoroughly test infected. Excellent! You're undoubtedly producing more robust, less buggy software faster and at lower cost. Sadly, it wasn't always this way. You're saddled with a large legacy of untested code. Test first development is not an option. Nonetheless unit testing, JUnit, and test driven de...
if you have no other mechanism for testing, start a local copy of your app in a separate process and actually make requests against it. not sure if django offers a way to run an isolated test server instance. but you'll probably end up needing to set up a local copy of the database as well if you don't already have one. it's a lot of work, but it's worth the effort in my experience
https://www.amazon.com/Unit-Testing-Principles-Practices-Patterns/dp/1617296279
this guy explains why, what for and with which goals exist to test
https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530
this guy shows how to test on practice and teaches feeling how much working code shoud be written between tests
The most common usage case in Django Rest... is to test that for certain input u get expected output from your endpoitns ๐
local database in tests should participate preferably with same engine type and version as in prod
TLDR: good first goal to test that your code interacts correctly with db as expected / and your endpoints behave as expected
I already have a GitHub Actions workflow to automate building a docker container for the application. Was thinking of adding some tests to it now
seems like a good idea. challenge is to implement the tests now, and what exactly to test for as in behaviour
ideally "testing" is something you can and should do on your own developer machine. even if you can't do that for some reason and can only run in a CI-like environment, the same considerations apply.
Kinda vague question, but what exactly should I test when writing unit tests? Here's an example with Django:
class OrgLocation(models.Model):
org = models.OneToOneField(
Org, primary_key=True, on_delete=models.CASCADE, blank=True
)
Should I test that the OneToOneField links to an Org class, that the primary_key argument is True, etc? I understand that the policy is to not test the framework, but to test what you make with the framework. I'm still confused though.
Do you have a view with that model in yet?
Yes, I do
Test functions, not data structure declarations.
Test your own code, not the code of a framework. It was already tested.
Hi everyone, currently working on the Wapiti project, an open source vulnerability web scanner written in Python, i'm doing unit testing on that and I stumbled on a problem, I want to test an async method that is handling a keyboad interrupt event and involve typing on a terminal to choose how to end the process, I was wondering how to work around with pytest, if any of you has ever met such case i'll be glad to recieve some ressources or help regarding this issue
I can show you the code snippet if needed of course
you want to run async code inside pytest?
if you use https://pypi.org/project/pytest-asyncio/ you can write async def tests that otherwise work exactly like normal pytest tests
or if you're using the anyio library, it bundles its own version of that: https://anyio.readthedocs.io/en/stable/testing.html
(i think anyio is great anyway and recommend it in any async application)
maybe check out https://pypi.org/project/pexpect/
... I wonder if this is the sort of thing hypothesis could address....?
IIRC, Zac Hatfield~~-Jones ~~hangs out here but I don't remember his nickname.
+1 this sounds exactly like what hypothesis is for
(i think his name is Hatfield-Dodds, not Hatfield-Jones)
hypothesis can explore test data to find failures and then reduce the data to a "smallest" data that produces the failure. If it can explore subsets of test suites, that's new to me.
I mean.... if you write a test that runs pytest. But that seems pretty far fetched.
that sounds like something you might undertake. If you squint hard enough, isn't that what mutmut does? ๐
Closer to hypothesis I think ๐คฃ
I do dabble with running pytest programmatically in mutmut 3 (poc). It's not super fun.
So I made a python app and used pyinstaller to make it an .exe but when trying to run it you get all those windows defender hurdels. is that normal for how i made it an exe or did i mess up?
if you're collecting the test id's into a list first, then yes, you can have hypothesis sample from it
i have made my first discord bot, what the best way to test it? i have a private server with some alts to test it already, im just making sure this is the correct approach because it seems time consuming
I made my discord bot testable by... Minimizing discord code presence to intercepting input from it to CLI lib and rendering back answers.
Input is redirected to console interface library and CLI library renders answers back.
That makes bot easily testable locally, since no issue to write unit test invoking CLI commands
Final version I implemented with discordgo hooked to cobra-cli
But I am sure some python lib analogs can be found for same purpose
https://github.com/apacheli/discord-api-libs?tab=readme-ov-file#python
- Using stuff like argparse for example
Some after thoughts. u can simplify code base of Discord bot in python
by transforming Async madness to sync.
If u will wrap present Discord connecting related code to very localized parts
Which invoke the rest of code as asyncio.to_thread in thread for async friendliness
U can keep the rest of your code as a simple syncronous stuff and disregarding async completely.
right after this invokation should be nice looking calls to argparse
all your unit tests will be to test simple syncronous, locally executable code, calling if necessary simple synchronous libraries
with at maximum checking integration with CLI inteface ^_^ should be very pretty for yourself
Hello is It possible to have some package, where is pytest fixture and this fixture is registred via pytest11 entrypoint (this package is for fixtures and other testing tools) and then have another package which use these fixtures when I have installed first package?
Absolutely, thats how a number of official plugins do it
Just ensure the dependency is configured
Want to ask pytest users can I somehow use result of my fixture in the parametrize ?
Fixture and return model :
class UserModel(BaseModel):
username: str
password: str
@pytest.fixture
def user_data() -> UserModel:
user = TestsDataProvider.fake_user()
return user
test file :
class TestAuthorization:
some_test_functions....
@pytest.mark.xfail
@pytest.mark.parametrize("username, password", [(user_data.username, PASSWORD), (USERNAME, user_data.password)])
def test_wrong_username_or_password(self, user_data, username, password):
response = Session(username, password).authorize().response
assert response.status_code == requests.codes.bad_request
UserWrongCredentialsModel.model_validate_json(response.text)
assert response.json()["reason"] == "Bad credentials"
user_data.username and user_data.password don't work : Cannot find reference 'username' /'password' in function
Use a lambda or operator.attrgetter
I'll write a full example in a mo
class TestAuthorization:
# some_test_functions....
@pytest.mark.xfail
@pytest.mark.parametrize(
"username_fn, password_fn",
[
(lambda u: u.username, lambda _: PASSWORD),
(lambda _: USERNAME, lambda u: u.password),
],
)
def test_wrong_username_or_password(self, user_data, username_fn, password_fn):
username = username_fn(user_data)
password = password_fn(user_data)
response = Session(username, password).authorize().response
assert response.status_code == requests.codes.bad_request
UserWrongCredentialsModel.model_validate_json(response.text)
assert response.json()["reason"] == "Bad credentials"
@river cobalt ^
@hexed cloak thank for response, will check in a minute
@river cobalt did you know you can use return for any expression not just names
so when you do:
user = TestsDataProvider.fake_user()
return user
you can just do
return TestsDataProvider.fake_user()
ruff can autofix this for you https://docs.astral.sh/ruff/rules/unnecessary-assign/
Yep this working as expected, ty โฅ๏ธ
, lambda _ it something new to me, will research about
Yep u right each variable takes time to initialize before run, will improve my code)
lambda _: ... is just like a normal lambda that takes 1 input. The _ is convention for saying "I don't need this value" when you are provided one anyways. You could do the same with a lambda of any number of args lambda _, _: .... It also can come up when you don't care about the value, just the number of iterations for _ in range(5): or when you don't need values while unpacking x, y, _ = pos where pos is a 3 length tuple.
I have been doing software testing for a couple of years. I got into a conversation with a developer about automated testing. He was telling me that most automated tests are created by developers to catch parts of coding that may have broke due to updates to the code.
My question: is it common practice for developers to create automated tests while coding to do unit tests and the other similar testing?
Yes. Very.
My question: is it common practice for developers to create automated tests while coding to do unit tests and the other similar testing?
- not common for hobists, usually only rarest the most skilled one do it.
- among commercial devs it varies as well...
- if dev uses interpreted language and reached Middle rank proficiency, then 100% chance of usage
- juniors or people freelancers / wordpress devs / bad quality devs usually do not write tests
- they are kind of very common. People which are like that are super popular
- in static typed languages / (often they are compilable languages), it is extra challenging to test stuff. Once again middle and senior devs unit test. Juniors usually don't. Juniors can be having 10 years of work experience, or even 20 years.
- it is extra challenging to unit test frontend code a bit. Same stuff.
- frontend developers unable to test are commonly claiming themselves being middle/senior devs, but with lack of testing it is just exaggerating on their part
Tldr: it is common only for commercial devs from Middle rank proficiently and higher. For everyone else it is not
=========
P.s. if u have written project without unit testing in language extremely not friendly in its design and ecosystem in the first place, and legacy of the project counts 20 years of life... In such situation anyone could give up trying to cover it with auto tests.
U need to wield language at necessary mastery and very preferably project should be from the start made testable.
Fixing project made without testing later is extremely hard (difficulty is proportional to amount of already written code and how bad it is. Highly skilled dev will be able to certain reasonable project size to fix them)
I think this varies on what the code does, how many work on the code, how important the code is to making/losing money, and what language the code is written in, and different companies have different policies about this as well.
A lot of C/C++ will have unit tests and regression or simulation tests just because getting C to do anything is harder and is usually written for performance reasons which do require benchmark simulations. Some junior devs are compelled to write unit tests as part of training. But the large part this is totally the discretion of the developer to decide if investing time will make them more comfortable meeting the deadline vs meeting some other quality. Some devs will berate each other if they dont have unit tests. In all less than a quarter of all code is unit tested that I have come across.
thank you for the explanation. That helps a lot.
Thank you. That helps with me understanding. ๐
Also with regard to adding tests to code that has broken, a lot of times code evolves over time. In prototype stage perhaps no unit tests were done and the problem has not been properly defined or discovered. Code may have to be rewritten 2 or 3 times to get that right. This fragile code may have gone into prod with no auto testing and become important. Now an update is needed so what should the dev do and how much pressure is on that dev for time? It is really all about pressure.
Yeah, I was noticing the time pressure thing. The group of developers I am currently working with would love to write auto tests for the code, but don't have the time. And due to lack of funds are about to be let go. So, they came into the project for a short time and tried their best. But, sometimes when they would deploy to production what was working on staging for some reason broke when they deployed to production. They blamed some of that on the lack of auto tests.
We can clarify regarding juniors, that different companies have certain coding standards they uphold.
Depending on company standards of quality, all devs, including juniors will be obligated to write unit tests in order to submit their work
There could be difference in understanding how to test though. To unit test well, u need preferably restructuring code to make it more testable.
if the culture of testing is present in project from the start, it is easy to copy necessary code examples from your colleagues to make it work though
It is just some companies do not hold any standards of quality
in this case, all devs are juniors (or less) by default if they write many thousands code lines without unit testing coverage for commercial usage
it is difficult to test, when no one does it. When legacy of application code is going to... hell.
There needed some agreement among present devs on it
Super good to know. From what I have been told, there is no testing that was developed with the code, for the project I am currently on.
the time pressure thing is mostly bullshit reason.
Rapid response from unit tests regarding your code quality, saves tremendous amount of time needed to fix any bug or add any feature.
U will code faster with unit tests pretty much, or at least not slower
Then more code lines in project, then more time is saved
Without unit tests rapidly checking stuff locally, a huge amount of time is wasted in discovering bugs in prod
and then taking huge time to fix them and redeploy to test in prod, and then again discovering and repeating their very long to response cycle
Some manage to have staging environment for testing, but nevertheless...
local dev environment to test things is way more rapid (just seconds or minutes of time at most, which u can activate at any moment by yourself)
This is common thing, and is inline with my observations.
That seems like kind of a shame that it is common.
We can clarify though, that writing End to end tests are entirely different thing. (Selenium / Cypress are entirely different story)
I speak only about importance of Unit testing. Fully in programming language programmatic check of code, with granularity of their locality. + usually lightweight integration checks to interact with databases are fine and pretty much part of unit tests at this point.
If I wanted to write auto tests to help with the manual testing that I do, I would use a tool like Selenium?
@proper wind regarding time pressure thing.
I recommend reading Kent Beck carefully https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530
It is shown on the example there how u save time by going through test first approach
I do not think time pressure is a bullshit thing. It totally exists for different reasons and i see it all the time. Mostly the bigger the company the less unit testing that goes on because the political time pressure thing becomes more important than the get it right thing. I do agree that having unit tests are valuable over the long run. But people have to weigh up what is good for them in the long run.
i think time pressure for testing is pretty much problem of lack of skills thing.
Skilled enough dev will code and work faster with tests. Significantly faster (or at least taking equal time) and in better quality by magnitude.
Hmmm...I would guess that larger companies would bake in time for unit tests to be written. I suppose it depends upon the company in the end.
then most devs are unskilled. Im seeing over all more than 75 percent of apps with no or little tests are written
clarify what u wish to test manually
exactly! ๐ฏ
forms, billing, communications.
Selenium / Cypress are for e2e tests, which is automating manual tests for web products yes.
For things that requires interaction with browser.
Such tests are way more heavy/difficult to maintain and to write
Decision to use such tests should be made... very carefully
The software is complete web based. So, Selenium would be a tool I can use?
Hmmm...I understand it takes a long time to write the auto tests. And then if changes happen that effects how the auto test work, that it needs to be rewritten.
u should cover your application with unit tests first.
e2e tests are way more difficult and slower and harder to maintain
Good application in quality can be having all kin dof testing, but unit tests should be first
your Selenium/Cypress tests are UI e2e tests on this diagram
using JS Jest framework / Python unittest/pytest, is usually Unit testing (with some integration testing flavour)
this picture is having a bit incorrect definition of integration tests
Integration tests check that service works with integration to some... external service. Web server, database, third party api
this diagram shows preferable proportion between tests. Unit tests should be in amount 100 times more than UI tests
They are cheap, they are fast (rapid response time greatly matters for comfortable development), they are easy to maintain
I see. The overall picture is making more sense to me. Thanks. ๐
its compelling.
I do want to point out that prototype code mostly is the one that goes with very few tests because its discovery
Give a reading to https://www.amazon.com/Unit-Testing-Principles-Practices-Patterns/dp/B08XZRTWYC book
Essentially without tests u reach quickly critical mass, when only god/author knows what is going on in project and how to add new feature.
Few months pass => only god knows how. Adding any simplistic feature becomes taking week/weeks of time and full knowledge of a project
With testing any dev can quickly onboard onto project and add feature in very small time