Package: testflows.asserts
No magic, intuitive assertion library with descriptive error messages.
Works with Python’sassert statementand is inspired bypytestsupport for assertions andgrappa-py/grappadescriptive error messages.Currently supports only Python 3.6 or above.WhyNo special assertion methods.
Uses the defaultassert statement.No magic.
Assertion statements are not modified and the defaultAssertionErrorclass is not overridden.High performance.
No extra code is executed if the assertion does not fail unless the assertion has side effects.No external dependencies.Simple and clean API.Compatible with most Python test frameworks.UsageUseerrorfor a single assert statementfromtestflows.assertsimporterrorassert1==1,error()or useerrorscontext manager to wrap multiple assert statementsfromtestflows.assertsimporterrorswitherrors():assert1==1assert2==2and if you don’t want to abort when an assertion fails and would like to
keep going then theerrorscontext manager supports soft assertions through it’serrormethod.fromtestflows.assertsimporterrorswitherrors()assoft:withsoft.error():assert1==2assert2==2When an assertion fails a descriptive error message is produced.
For examplefromtestflows.assertsimporterrorassert1==2,error()produces the following outputAssertionError:Oops!AssertionfailedThefollowingassertionwasnotsatisfiedassert1==2,error()Assertionvaluesassert1==2,error()^is=Falseassert1==2,error()^isFalseWhereFile't.py',line3in'<module>'0|1|fromtestflows.assertsimporterror2|3|>assert1==2,error()HowTheassertsmodule works similarly to the old implementation ofpytestassertions. If the assertion fails, theassert statementis reinterpreted
to produce a detailed error message.Therefore, if the assertion statement has a side effect it might not
work as expected when an assertion fails.In thepytestframework, thisproblemis solved
by rewriting the original assertion.
Theassertsmodule solves thisproblemby explicitly usingvaluescontext manager
to store the values of the expression that has a side effect.Installation$./build;./installwhere$./buildcreates a pip installable package in./dist, for example$lsdist/testflows.asserts-4.1.190811.155018.tar.gzand$./installusessudo pip installcommand to perform the system-wide installation.Assertions with side-effectsIf assertion has side effects thenvaluescontext manager can be used to
address thisproblem.The example below demonstrates theproblem.fromtestflows.assertsimporterrorbuf=[1]assertbuf.append(2)andbuf,error()In the code above, the assertion fails and thebuflist is modified twice. Once
when the assertion fails and once when the assertion is reinterpreted whenerror()method is evaluated.The error message that is produced shows theproblemThefollowingassertionwasnotsatisfiedassertbuf.append(2)andbuf,error()Assertionvaluesassertbuf.append(2)andbuf,error()^is[1,2,2]assertbuf.append(2)andbuf,error()^is=<built-inmethodappendoflistobjectat0x7f13d1c41248>assertbuf.append(2)andbuf,error()^is=Noneassertbuf.append(2)andbuf,error()^is[1,2,2]assertbuf.append(2)andbuf,error()^is=Noneassertbuf.append(2)andbuf,error()^isFalseWhereFile't.py',line4in'<module>'1|fromtestflows.assertsimporterror2|3|buf=[1]4|>assertbuf.append(2)andbuf,error()specifically, the lines below show that value ofbufis [1,2,2] instead
of the desired value of [1,2]Assertionvaluesassertbuf.append(2)andbuf,error()^is[1,2,2]In order to work around thisproblem,valuescontext manager can be used
as followsfromtestflows.assertsimportvalues,errorbuf=[1]withvalues()asthat:assertthat(buf.append(2))andbuf,error()and it will produce the error messageThefollowingassertionwasnotsatisfiedassertthat(buf.append(2))andbuf,error()Assertionvaluesassertthat(buf.append(2))andbuf,error()^is=Noneassertthat(buf.append(2))andbuf,error()^is[1,2]assertthat(buf.append(2))andbuf,error()^is=Noneassertthat(buf.append(2))andbuf,error()^isFalseWhereFile't.py',line5in'<module>'1|fromtestflows.assertsimportvalues,error2|3|buf=[1]4|withvalues()asthat:5|>assertthat(buf.append(2))andbuf,error()the lines below show that thebuflist has the expected value of [1,2]assertthat(buf.append(2))andbuf,error()^is[1,2]this is because the expression passed tothatis not reinterpreted and only the
result of the expression is stored and used during the generation of the error message.The explicit use ofvaluescontext manager provides a simple solution without
any need to rewrite the original assertion statement.