How do people write unit tests with Ignition? I have finally, FINALLY, refactored this project and completely decoupled the business logic from the GUI and so the first thing I want to do is write some unit tests so anytime we make a change, we can check all the usual processes and make sure nothing unexpectedly broke, move away from the "production is the QA environment" paradigm we have going on now.
This app is 99% CRUD routes for various db forms. So right now I am writing functions that are testing the creation/update/deleting of records and checking I get the appropriate result.
Here's my first attempt -
def customerTests():
# Create a new customer, customer name TestCustomer1000
newCustomer = {...}
newCreateResult = forms2.Forms.Customer.create(newCustomer)
print 'creating customer'
assert newCreateResult.success == True
print 'passed'
# Update the new customer to TestCustomer1001
updateCustomerData = {...}
# newCreateResult.result is the idx of the newly created one
customerUpdateResult = forms2.Forms.Customer.update(updateCustomerData, newCustomer, newCreateResult.result)
print 'updating..'
assert customerUpdateResult.success == True
print 'passed'
# Try to update customer name to existing Customer Name- this should fail
updateToExistingCustomerName = {...}
shouldFailUpdate = forms2.Forms.Customer.update(updateToMesser, updateCustomerData, newCreateResult.result)
print 'trying fail update'
assert shouldFailUpdate.success == False
print 'passed'
# Delete the new customer
newDeleteResult = forms2.Forms.Customer.delete(newCreateResult.result)
print 'deleting..'
assert newDeleteResult.success == True
print 'passed'
And then I would call this and just make sure no assertion error comes up. I am wondering if this is how most people do it or if there is other better methods for writing unit tests specifically within the context of Ignition.
While this won't make you design better tests, it can be helpful to write them.
click for code
import ast
"""
Basic test helper
Import test in your file: from utils.test import test
Decorate your functions to be tested:
@test
def test_foo():
foo = "foo"
bar = get_bar()
assert foo == bar, "expected {}, got {}".format(foo, bar)
Call the function individually, or use run_tests() to run all the marked functions in modules:
run_tests(module_1, module_b)
"""
class TestFinder(ast.NodeVisitor):
def visit_Module(self, node):
self.test_funcs = []
self.generic_visit(node)
def visit_FunctionDef(self, node):
if "test" in (deco.id for deco in node.decorator_list):
self.test_funcs.append(node.name)
def get_testfuncs(self):
return self.test_funcs
def test(func):
"""
Decorator to mark functions to be tested.
Simply import the decorator (from Tests.utils import test) and add @test before the function
"""
def wrapper():
try:
func()
except AssertionError as e:
message = "failed ({})".format(e)
else:
message = "passed"
return message
return wrapper
def run_tests(*modules):
"""
Run all the functions marked as tests (with the test decorator) in every packages passed as parameter.
"""
for m in modules:
print("{}\ntesting functions in {}...".format("-"*20, m.name))
tree = ast.parse(m.code)
f = TestFinder()
f.visit(tree)
funcs = f.get_testfuncs()
if not funcs:
print("No functions marked for testing found in {}".format(m.name))
for f in funcs:
try:
message = getattr(m, f)()
print("{:.<40}{}".format(f, message))
except BaseException as e:
print(repr(e))
Write your tests as simple functions, decorate them with @test, then run run_test(module1, module2, etc) wherever you want (usually the script console though).
I haven't used it in a while, and if I remember correctly there were a few quirks. I may or may not have fixed them.
edit: forgot to format code :X
note: You can use run_tests() to run all the tests in the modules passed as arguments, or just call a function that's decorated with @test directly