Mock default attribute of SQLAlchemy
I have some issues to mock a SQLAlchemy object when using the default
and onupdate
fields in my models :
def get_uuid():
return str(uuid.uuid4())
def get_now():
return db.func.now()
class BaseModel(db.Model):
__abstract__ = True
id = db.Column(UUIDType(binary=False), primary_key=True, nullable=False, default=get_uuid)
created_at = db.Column(db.DateTime(timezone=True), default=get_now(), nullable=False, index=True)
The get_now()
and get_uuid()
behaviour do not change even when I try to mock them in my tests :
def test_create_source(client, mocker):
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('myproject.models.get_uuid', mock)
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('myproject.models.get_now', mock)
resp = client.post('/sources', json={'name': 'My source'})
assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
### Results :
> assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
E AssertionError: assert {'createdAt':...17:38:38 GMT'} == {'createdAt': ...00:00:00 GMT'}
E Omitting 1 identical items, use -vv to show
E Differing items:
E {'id': '8eb074c0-41e9-436c-8f71-b4c6842f4809'} != {'id': '123e4567-e89b-12d3-a456-426655440000'}
E {'createdAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E {'updatedAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E Use -v to get the full diff
tests/test_sources.py:17: AssertionError
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here. It's explained in the "Mocking class helpers" part of this post but I still was not able to fix my issue :(
The full runnable code to reproduce the problem is available here : https://github.com/ncrocfer/flaskmock
Do you have some ideas please ?
python testing flask sqlalchemy pytest
add a comment |
I have some issues to mock a SQLAlchemy object when using the default
and onupdate
fields in my models :
def get_uuid():
return str(uuid.uuid4())
def get_now():
return db.func.now()
class BaseModel(db.Model):
__abstract__ = True
id = db.Column(UUIDType(binary=False), primary_key=True, nullable=False, default=get_uuid)
created_at = db.Column(db.DateTime(timezone=True), default=get_now(), nullable=False, index=True)
The get_now()
and get_uuid()
behaviour do not change even when I try to mock them in my tests :
def test_create_source(client, mocker):
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('myproject.models.get_uuid', mock)
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('myproject.models.get_now', mock)
resp = client.post('/sources', json={'name': 'My source'})
assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
### Results :
> assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
E AssertionError: assert {'createdAt':...17:38:38 GMT'} == {'createdAt': ...00:00:00 GMT'}
E Omitting 1 identical items, use -vv to show
E Differing items:
E {'id': '8eb074c0-41e9-436c-8f71-b4c6842f4809'} != {'id': '123e4567-e89b-12d3-a456-426655440000'}
E {'createdAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E {'updatedAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E Use -v to get the full diff
tests/test_sources.py:17: AssertionError
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here. It's explained in the "Mocking class helpers" part of this post but I still was not able to fix my issue :(
The full runnable code to reproduce the problem is available here : https://github.com/ncrocfer/flaskmock
Do you have some ideas please ?
python testing flask sqlalchemy pytest
add a comment |
I have some issues to mock a SQLAlchemy object when using the default
and onupdate
fields in my models :
def get_uuid():
return str(uuid.uuid4())
def get_now():
return db.func.now()
class BaseModel(db.Model):
__abstract__ = True
id = db.Column(UUIDType(binary=False), primary_key=True, nullable=False, default=get_uuid)
created_at = db.Column(db.DateTime(timezone=True), default=get_now(), nullable=False, index=True)
The get_now()
and get_uuid()
behaviour do not change even when I try to mock them in my tests :
def test_create_source(client, mocker):
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('myproject.models.get_uuid', mock)
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('myproject.models.get_now', mock)
resp = client.post('/sources', json={'name': 'My source'})
assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
### Results :
> assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
E AssertionError: assert {'createdAt':...17:38:38 GMT'} == {'createdAt': ...00:00:00 GMT'}
E Omitting 1 identical items, use -vv to show
E Differing items:
E {'id': '8eb074c0-41e9-436c-8f71-b4c6842f4809'} != {'id': '123e4567-e89b-12d3-a456-426655440000'}
E {'createdAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E {'updatedAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E Use -v to get the full diff
tests/test_sources.py:17: AssertionError
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here. It's explained in the "Mocking class helpers" part of this post but I still was not able to fix my issue :(
The full runnable code to reproduce the problem is available here : https://github.com/ncrocfer/flaskmock
Do you have some ideas please ?
python testing flask sqlalchemy pytest
I have some issues to mock a SQLAlchemy object when using the default
and onupdate
fields in my models :
def get_uuid():
return str(uuid.uuid4())
def get_now():
return db.func.now()
class BaseModel(db.Model):
__abstract__ = True
id = db.Column(UUIDType(binary=False), primary_key=True, nullable=False, default=get_uuid)
created_at = db.Column(db.DateTime(timezone=True), default=get_now(), nullable=False, index=True)
The get_now()
and get_uuid()
behaviour do not change even when I try to mock them in my tests :
def test_create_source(client, mocker):
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('myproject.models.get_uuid', mock)
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('myproject.models.get_now', mock)
resp = client.post('/sources', json={'name': 'My source'})
assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
### Results :
> assert resp.json == {
'name': 'My source',
'id': '123e4567-e89b-12d3-a456-426655440000',
'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT',
'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'
}
E AssertionError: assert {'createdAt':...17:38:38 GMT'} == {'createdAt': ...00:00:00 GMT'}
E Omitting 1 identical items, use -vv to show
E Differing items:
E {'id': '8eb074c0-41e9-436c-8f71-b4c6842f4809'} != {'id': '123e4567-e89b-12d3-a456-426655440000'}
E {'createdAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'createdAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E {'updatedAt': 'Fri, 18 Jan 2019 17:38:38 GMT'} != {'updatedAt': 'Tue, 01 Jan 2019 00:00:00 GMT'}
E Use -v to get the full diff
tests/test_sources.py:17: AssertionError
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here. It's explained in the "Mocking class helpers" part of this post but I still was not able to fix my issue :(
The full runnable code to reproduce the problem is available here : https://github.com/ncrocfer/flaskmock
Do you have some ideas please ?
python testing flask sqlalchemy pytest
python testing flask sqlalchemy pytest
asked Jan 18 at 17:45
ncrocferncrocfer
1,64541533
1,64541533
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here.
Close: you've passed a reference to function get_uuid()
as default to id
and the result of calling get_now()
(a function expression object) as default to created_at
. Changing what those names are bound to in the module after the fact has no effect anymore on the columns, which already hold references to the objects themselves.
In case of get_uuid()
you should mock the function it is calling:
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('uuid.uuid4', mock)
and in case of get_now()
you should consider not calling it during model construction:
class BaseModel(db.Model):
...
created_at = db.Column(..., default=get_now, ...)
so that you can again mock the actual function it is calling:
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('sqlalchemy.func.now', mock)
On the other hand perhaps you should not be asserting anything about id
and the timestamps in the test, since it seems that the important thing is to verify that the name was set correctly.
Thank you for your answzer and your explanation Ilja ! Your solution works very well for the uuid mock, but SQLAlchemy does not seem to like when I do not call theget_now
function during the model construction :sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input. [SQL: 'INSERT INTO sources (id, created_at, updated_at, name) VALUES (?, ?, ?, ?)'] [parameters: [{'name': 'My source'}]]
– ncrocfer
Jan 19 at 14:18
That's an oversight on my part, and a bit trickier to handle. Will have to ponder a bit. It's a result of the default function producing something other than a Pythondatetime
during execution (SQLA special cases passing an sql expression object as default during construction, or so).
– Ilja Everilä
Jan 19 at 14:43
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54259056%2fmock-default-attribute-of-sqlalchemy%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here.
Close: you've passed a reference to function get_uuid()
as default to id
and the result of calling get_now()
(a function expression object) as default to created_at
. Changing what those names are bound to in the module after the fact has no effect anymore on the columns, which already hold references to the objects themselves.
In case of get_uuid()
you should mock the function it is calling:
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('uuid.uuid4', mock)
and in case of get_now()
you should consider not calling it during model construction:
class BaseModel(db.Model):
...
created_at = db.Column(..., default=get_now, ...)
so that you can again mock the actual function it is calling:
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('sqlalchemy.func.now', mock)
On the other hand perhaps you should not be asserting anything about id
and the timestamps in the test, since it seems that the important thing is to verify that the name was set correctly.
Thank you for your answzer and your explanation Ilja ! Your solution works very well for the uuid mock, but SQLAlchemy does not seem to like when I do not call theget_now
function during the model construction :sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input. [SQL: 'INSERT INTO sources (id, created_at, updated_at, name) VALUES (?, ?, ?, ?)'] [parameters: [{'name': 'My source'}]]
– ncrocfer
Jan 19 at 14:18
That's an oversight on my part, and a bit trickier to handle. Will have to ponder a bit. It's a result of the default function producing something other than a Pythondatetime
during execution (SQLA special cases passing an sql expression object as default during construction, or so).
– Ilja Everilä
Jan 19 at 14:43
add a comment |
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here.
Close: you've passed a reference to function get_uuid()
as default to id
and the result of calling get_now()
(a function expression object) as default to created_at
. Changing what those names are bound to in the module after the fact has no effect anymore on the columns, which already hold references to the objects themselves.
In case of get_uuid()
you should mock the function it is calling:
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('uuid.uuid4', mock)
and in case of get_now()
you should consider not calling it during model construction:
class BaseModel(db.Model):
...
created_at = db.Column(..., default=get_now, ...)
so that you can again mock the actual function it is calling:
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('sqlalchemy.func.now', mock)
On the other hand perhaps you should not be asserting anything about id
and the timestamps in the test, since it seems that the important thing is to verify that the name was set correctly.
Thank you for your answzer and your explanation Ilja ! Your solution works very well for the uuid mock, but SQLAlchemy does not seem to like when I do not call theget_now
function during the model construction :sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input. [SQL: 'INSERT INTO sources (id, created_at, updated_at, name) VALUES (?, ?, ?, ?)'] [parameters: [{'name': 'My source'}]]
– ncrocfer
Jan 19 at 14:18
That's an oversight on my part, and a bit trickier to handle. Will have to ponder a bit. It's a result of the default function producing something other than a Pythondatetime
during execution (SQLA special cases passing an sql expression object as default during construction, or so).
– Ilja Everilä
Jan 19 at 14:43
add a comment |
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here.
Close: you've passed a reference to function get_uuid()
as default to id
and the result of calling get_now()
(a function expression object) as default to created_at
. Changing what those names are bound to in the module after the fact has no effect anymore on the columns, which already hold references to the objects themselves.
In case of get_uuid()
you should mock the function it is calling:
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('uuid.uuid4', mock)
and in case of get_now()
you should consider not calling it during model construction:
class BaseModel(db.Model):
...
created_at = db.Column(..., default=get_now, ...)
so that you can again mock the actual function it is calling:
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('sqlalchemy.func.now', mock)
On the other hand perhaps you should not be asserting anything about id
and the timestamps in the test, since it seems that the important thing is to verify that the name was set correctly.
I think it's because my models and its attributes are already imported and evaluated before doing my test, so the mock is useless here.
Close: you've passed a reference to function get_uuid()
as default to id
and the result of calling get_now()
(a function expression object) as default to created_at
. Changing what those names are bound to in the module after the fact has no effect anymore on the columns, which already hold references to the objects themselves.
In case of get_uuid()
you should mock the function it is calling:
mock = mocker.MagicMock(return_value='123e4567-e89b-12d3-a456-426655440000')
mocker.patch('uuid.uuid4', mock)
and in case of get_now()
you should consider not calling it during model construction:
class BaseModel(db.Model):
...
created_at = db.Column(..., default=get_now, ...)
so that you can again mock the actual function it is calling:
mock = mocker.MagicMock(return_value=datetime.datetime(2019, 1, 1))
mocker.patch('sqlalchemy.func.now', mock)
On the other hand perhaps you should not be asserting anything about id
and the timestamps in the test, since it seems that the important thing is to verify that the name was set correctly.
edited Jan 19 at 10:49
answered Jan 19 at 10:44
Ilja EveriläIlja Everilä
23.8k33762
23.8k33762
Thank you for your answzer and your explanation Ilja ! Your solution works very well for the uuid mock, but SQLAlchemy does not seem to like when I do not call theget_now
function during the model construction :sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input. [SQL: 'INSERT INTO sources (id, created_at, updated_at, name) VALUES (?, ?, ?, ?)'] [parameters: [{'name': 'My source'}]]
– ncrocfer
Jan 19 at 14:18
That's an oversight on my part, and a bit trickier to handle. Will have to ponder a bit. It's a result of the default function producing something other than a Pythondatetime
during execution (SQLA special cases passing an sql expression object as default during construction, or so).
– Ilja Everilä
Jan 19 at 14:43
add a comment |
Thank you for your answzer and your explanation Ilja ! Your solution works very well for the uuid mock, but SQLAlchemy does not seem to like when I do not call theget_now
function during the model construction :sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input. [SQL: 'INSERT INTO sources (id, created_at, updated_at, name) VALUES (?, ?, ?, ?)'] [parameters: [{'name': 'My source'}]]
– ncrocfer
Jan 19 at 14:18
That's an oversight on my part, and a bit trickier to handle. Will have to ponder a bit. It's a result of the default function producing something other than a Pythondatetime
during execution (SQLA special cases passing an sql expression object as default during construction, or so).
– Ilja Everilä
Jan 19 at 14:43
Thank you for your answzer and your explanation Ilja ! Your solution works very well for the uuid mock, but SQLAlchemy does not seem to like when I do not call the
get_now
function during the model construction : sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input. [SQL: 'INSERT INTO sources (id, created_at, updated_at, name) VALUES (?, ?, ?, ?)'] [parameters: [{'name': 'My source'}]]
– ncrocfer
Jan 19 at 14:18
Thank you for your answzer and your explanation Ilja ! Your solution works very well for the uuid mock, but SQLAlchemy does not seem to like when I do not call the
get_now
function during the model construction : sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite DateTime type only accepts Python datetime and date objects as input. [SQL: 'INSERT INTO sources (id, created_at, updated_at, name) VALUES (?, ?, ?, ?)'] [parameters: [{'name': 'My source'}]]
– ncrocfer
Jan 19 at 14:18
That's an oversight on my part, and a bit trickier to handle. Will have to ponder a bit. It's a result of the default function producing something other than a Python
datetime
during execution (SQLA special cases passing an sql expression object as default during construction, or so).– Ilja Everilä
Jan 19 at 14:43
That's an oversight on my part, and a bit trickier to handle. Will have to ponder a bit. It's a result of the default function producing something other than a Python
datetime
during execution (SQLA special cases passing an sql expression object as default during construction, or so).– Ilja Everilä
Jan 19 at 14:43
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54259056%2fmock-default-attribute-of-sqlalchemy%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown