https://prefect.io logo
m

Matt

10/01/2020, 11:12 PM
Hi! I'm looking for good design pattern for unit testing tasks. I've seen the examples that compose and test flows but it makes more sense to me to start with a test for each of my tasks instead.
Writing a test like this seems to work just fine...
However, I'm stuck trying to run tasks that require inputs. I can see it's possible to set an upstream state from the run command, but not sure how to populate a string list that I would normally be populating with a Parameter.
It's also making me feel like I don't have a solid grasp on states and task initialization in general despite having gone through the docs pretty carefully.
Effectively, I'm trying to do this:
But I know I need to create or mock a State, Context, Parameter or something to that effect. Not sure which.
n

nicholas

10/01/2020, 11:19 PM
Hi @Matt! One of the truly great things about Prefect tasks is that they're just normal python functions, meaning you can unit test them as you would any other python application. As such, you can directly feed any inputs to your task as you would expect at runtime. Some resources I would recommend would be the testing documentation and Prefect's own suite of tests, which run against Prefect itself
m

Matt

10/01/2020, 11:19 PM
Would love some help from the community! And/or some direction to good examples on how to test Prefect tasks/flows.
Hi @nicholas. I've taken a look at those docs but haven't been able to make much progress. Calling the tasks without the TaskRunner gets me a "Could not infer an active Flow context." error. My tasks are looking for prefect.config and prefect.context, btw, so at the very least I'd have to mock those. I think I'd rather figure out how to mock the inputs.
I haven't been able to find good examples in the Prefect tests but there's a lot of stuff there. Any in particular you could point me to? Thanks in advance!
c

Chris White

10/01/2020, 11:46 PM
Chiming in here — all tasks have a
.run()
method that routes inputs directly to the task as a python function. E.g.
Copy code
@task
def my_task(x, y):
    return x + y

assert my_task.run(1, 2) == 3
if you reference things like
prefect.context
within your task, you might have to set up some scaffolding:
Copy code
with prefect.context(my_special_key=value):
    my_task.run(1, 2)
but that’s on a case-by-case basis
upvote 1
m

Matt

10/02/2020, 12:02 AM
Thanks @Chris White. This approach definitely works as a way to call tasks with an input. It's somewhat complicated in that my tasks don't all return something (though maybe I need to think that through). It seems to me the downside is that on the assertion side I can't then do a simple is_successful() to see if the task worked or not. I'd need to figure out another way to see if the task worked. That right?
c

Chris White

10/02/2020, 12:05 AM
Yea so then you would need to return to your original pattern of using the task runner. In that case you might look at this test file to see what setup is and is not required for that: https://github.com/PrefectHQ/prefect/blob/master/tests/engine/test_task_runner.py In particular, if you test specifically the runner’s “get task run state” method it should have the minimal interface you’re looking for: https://github.com/PrefectHQ/prefect/blob/master/tests/engine/test_task_runner.py#L987
🙌 1
m

Matt

10/02/2020, 12:43 AM
This is perfect! Thanks @Chris White! Will look at this more but was able to use this approach to do my test. The test_inputs on line 1068 was what I needed.
👍 1
BTW, in terms of feedback, if there was some way to run a task like this I think it'd be more intuitive given the "get_task_run_state" method isn't a normal approach. This code fails because it's missing some context which presumably would need to get mocked somehow, but that's the gist of what I would be hoping for.
👍 1
c

Chris White

10/02/2020, 2:39 AM
Good to know - in the meantime, I’ll archive this thread to GitHub in case anyone else has similar questions, hopefully it can help them out too
👍 1
@Marvin archive “How to best unit test individual tasks with a TaskRunner?”
p

Pedro Machado

10/02/2020, 2:41 AM
This is definitely useful. What's a good pattern to import the tasks from the file that contains the flow in your tests?
c

Chris White

10/02/2020, 2:53 AM
Standard python import rules apply depending on the structure of your project and where you run your tests; you can also get tasks from your Flow via the
flow.get_tasks
method