5

I have read this Q&A, and already try to catch exception on my code that raise an IntegrityError exception, this way :

self.assertRaises(IntegrityError, db.session.commit())

But somehow my unit test still failed and stop with IntegrityError exception. I expect it to say OK as I already expect to have exception in my unit test. This was cause by code that tries to insert row having the same unique field values.

Any idea?

Community
  • 1
  • 1
swdev
  • 4,997
  • 8
  • 64
  • 106

2 Answers2

6

One of these will to the trick:

# ... only if version >= 2.7
with self.assertRaises(IntegrityError):
    db.session.commit()

Or:

self.assertRaises(IntegrityError, db.session.commit)

The difference between your example and the correct way is:

# Your example: You call db.session.commit(), this will raise an exception before
# assertRaises is called
self.assertRaises(IntegrityError, db.session.commit())

# Correct way: Pass what should be called to assertRaises, 
# let assertRaises invoke it and check for exception
self.assertRaises(IntegrityError, db.session.commit)

I prefer to use assertRaises as a context manager (using with).

codeape
  • 97,830
  • 24
  • 159
  • 188
  • Phew.. this solved and brighten my day! Thanks! :) Right, I was thinking earlier that the argument accept function name, not call of the function. But, somehow I miss that when I do the actual code. But, why do you prefer to use a context manager? Isn't with this single line the result will be the same? – swdev Oct 10 '13 at 07:39
  • Added comment,I just use context manager as you pointed out, and I think the other benefit is that we can expand/refine our code much more in that indented block. I am still new in python, so that's what I am getting :) – swdev Oct 10 '13 at 07:41
  • 1
    I agree. I think using assertRaises as a context manager makes the test code clearer. – codeape Oct 10 '13 at 09:28
0

I've just spent a few hours trying to understand why my test was failing with IntegrityError during execution, but failed to catch it with with pytest.raises block (session builder is simplified, but notice autocommit flag):

async with async_session_maker(autocommit=True) as session:
    with pytest.raises(sqlalchemy.exc.IntegrityError):
        sqlachemy.execute(statement_which_violates_foreign_key_contstraint)

Trouble appeared on an order of session block and pytest block. The exception will be raised on session.commit() statement which is hidden in __aexit__ method of AsyncSession.

Solution - change the order:

with pytest.raises(sqlalchemy.exc.IntegrityError):
    async with async_session_maker(autocommit=True) as session:
        sqlachemy.execute(statement_which_violates_foreign_key_contstraint)
Serge Norin
  • 101
  • 1
  • 2