Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
0d27b5ed
Commit
0d27b5ed
authored
Apr 21, 2016
by
Renzo Lucioni
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #12215 from edx/renzo/program-factory
Retrofit programs data mixin with factories
parents
f8f5e703
1ffa81f7
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
127 additions
and
254 deletions
+127
-254
common/test/acceptance/fixtures/programs.py
+5
-56
lms/djangoapps/learner_dashboard/tests/test_programs.py
+27
-30
openedx/core/djangoapps/programs/tests/factories.py
+54
-0
openedx/core/djangoapps/programs/tests/mixins.py
+41
-168
No files found.
common/test/acceptance/fixtures/programs.py
View file @
0d27b5ed
...
...
@@ -4,67 +4,16 @@ Tools to create programs-related data for use in bok choy tests.
from
collections
import
namedtuple
import
json
import
factory
import
requests
from
.
import
PROGRAMS_STUB_URL
from
.config
import
ConfigModelFixture
from
openedx.core.djangoapps.programs.tests
import
factories
FakeProgram
=
namedtuple
(
'FakeProgram'
,
[
'name'
,
'status'
,
'org_key'
,
'course_id'
])
class
Program
(
factory
.
Factory
):
"""
Factory for stubbing program resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
id
=
factory
.
Sequence
(
lambda
n
:
n
)
# pylint: disable=invalid-name
name
=
'dummy-program-name'
subtitle
=
'dummy-program-subtitle'
category
=
'xseries'
status
=
'unpublished'
marketing_slug
=
factory
.
Sequence
(
lambda
n
:
'slug-{}'
.
format
(
n
))
# pylint: disable=unnecessary-lambda
organizations
=
[]
course_codes
=
[]
banner_image_urls
=
{}
class
Organization
(
factory
.
Factory
):
"""
Factory for stubbing nested organization resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
key
=
'dummyX'
display_name
=
'dummy-org-display-name'
class
CourseCode
(
factory
.
Factory
):
"""
Factory for stubbing nested course code resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
display_name
=
'dummy-org-display-name'
run_modes
=
[]
class
RunMode
(
factory
.
Factory
):
"""
Factory for stubbing nested run mode resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
course_key
=
'org/course/run'
mode_slug
=
'verified'
class
ProgramsFixture
(
object
):
"""
Interface to set up mock responses from the Programs stub server.
...
...
@@ -78,11 +27,11 @@ class ProgramsFixture(object):
"""
programs
=
[]
for
program
in
fake_programs
:
run_mode
=
RunMode
(
course_key
=
program
.
course_id
)
course_code
=
CourseCode
(
run_modes
=
[
run_mode
])
org
=
Organization
(
key
=
program
.
org_key
)
run_mode
=
factories
.
RunMode
(
course_key
=
program
.
course_id
)
course_code
=
factories
.
CourseCode
(
run_modes
=
[
run_mode
])
org
=
factories
.
Organization
(
key
=
program
.
org_key
)
program
=
Program
(
program
=
factories
.
Program
(
name
=
program
.
name
,
status
=
program
.
status
,
organizations
=
[
org
],
...
...
lms/djangoapps/learner_dashboard/tests/test_programs.py
View file @
0d27b5ed
...
...
@@ -8,7 +8,6 @@ from urlparse import urljoin
from
django.conf
import
settings
from
django.core.urlresolvers
import
reverse
from
django.http
import
HttpResponseRedirect
from
django.test
import
override_settings
from
edx_oauth2_provider.tests.factories
import
ClientFactory
from
opaque_keys.edx
import
locator
...
...
@@ -39,6 +38,7 @@ class TestProgramListing(
Unit tests for getting the list of programs enrolled by a logged in user
"""
PASSWORD
=
'test'
url
=
reverse
(
'program_listing_view'
)
def
setUp
(
self
):
"""
...
...
@@ -81,10 +81,9 @@ class TestProgramListing(
"""
self
.
mock_programs_api
()
self
.
client
.
login
(
username
=
self
.
student
.
username
,
password
=
self
.
PASSWORD
)
response
=
self
.
client
.
get
(
reverse
(
"program_listing_view"
))
self
.
assertEqual
(
response
.
status_code
,
200
)
response
=
self
.
client
.
get
(
self
.
url
)
x_series_url
=
urljoin
(
settings
.
MKTG_URLS
.
get
(
'ROOT'
),
'xseries'
)
self
.
assert
In
(
x_series_url
,
response
.
content
)
self
.
assert
Contains
(
response
,
x_series_url
)
return
response
def
_get_program_checklist
(
self
,
program_id
):
...
...
@@ -101,18 +100,18 @@ class TestProgramListing(
def
test_get_program_with_no_enrollment
(
self
):
response
=
self
.
_setup_and_get_program
()
for
program_element
in
self
.
_get_program_checklist
(
0
):
self
.
assertNot
In
(
program_element
,
response
.
cont
ent
)
self
.
assertNot
Contains
(
response
,
program_elem
ent
)
for
program_element
in
self
.
_get_program_checklist
(
1
):
self
.
assertNot
In
(
program_element
,
response
.
cont
ent
)
self
.
assertNot
Contains
(
response
,
program_elem
ent
)
@httpretty.activate
def
test_get_one_program
(
self
):
self
.
_create_course_and_enroll
(
self
.
student
,
*
self
.
COURSE_KEYS
[
0
]
.
split
(
'/'
))
response
=
self
.
_setup_and_get_program
()
for
program_element
in
self
.
_get_program_checklist
(
0
):
self
.
assert
In
(
program_element
,
response
.
cont
ent
)
self
.
assert
Contains
(
response
,
program_elem
ent
)
for
program_element
in
self
.
_get_program_checklist
(
1
):
self
.
assertNot
In
(
program_element
,
response
.
cont
ent
)
self
.
assertNot
Contains
(
response
,
program_elem
ent
)
@httpretty.activate
def
test_get_both_program
(
self
):
...
...
@@ -120,32 +119,34 @@ class TestProgramListing(
self
.
_create_course_and_enroll
(
self
.
student
,
*
self
.
COURSE_KEYS
[
5
]
.
split
(
'/'
))
response
=
self
.
_setup_and_get_program
()
for
program_element
in
self
.
_get_program_checklist
(
0
):
self
.
assert
In
(
program_element
,
response
.
cont
ent
)
self
.
assert
Contains
(
response
,
program_elem
ent
)
for
program_element
in
self
.
_get_program_checklist
(
1
):
self
.
assert
In
(
program_element
,
response
.
cont
ent
)
self
.
assert
Contains
(
response
,
program_elem
ent
)
def
test_get_programs_dashboard_not_enabled
(
self
):
self
.
create_programs_config
(
program_listing_enabled
=
False
)
self
.
client
.
login
(
username
=
self
.
student
.
username
,
password
=
self
.
PASSWORD
)
response
=
self
.
client
.
get
(
reverse
(
"program_listing_view"
)
)
response
=
self
.
client
.
get
(
self
.
url
)
self
.
assertEqual
(
response
.
status_code
,
404
)
def
test_xseries_advertise_disabled
(
self
):
self
.
create_programs_config
(
program_listing_enabled
=
True
,
xseries_ad_enabled
=
False
)
self
.
client
.
login
(
username
=
self
.
student
.
username
,
password
=
self
.
PASSWORD
)
response
=
self
.
client
.
get
(
reverse
(
"program_listing_view"
))
self
.
assertEqual
(
response
.
status_code
,
200
)
response
=
self
.
client
.
get
(
self
.
url
)
x_series_url
=
urljoin
(
settings
.
MKTG_URLS
.
get
(
'ROOT'
),
'xseries'
)
self
.
assertNot
In
(
x_series_url
,
response
.
content
)
self
.
assertNot
Contains
(
response
,
x_series_url
)
def
test_get_programs_not_logged_in
(
self
):
self
.
create_programs_config
()
response
=
self
.
client
.
get
(
reverse
(
"program_listing_view"
))
self
.
assertEqual
(
response
.
status_code
,
302
)
self
.
assertIsInstance
(
response
,
HttpResponseRedirect
)
self
.
assertIn
(
'login'
,
response
.
url
)
# pylint: disable=no-member
response
=
self
.
client
.
get
(
self
.
url
)
def
_expected_credetials_data
(
self
):
self
.
assertRedirects
(
response
,
'{}?next={}'
.
format
(
reverse
(
'signin_user'
),
self
.
url
)
)
# TODO: Use a factory to generate this data.
def
_expected_credentials_data
(
self
):
""" Dry method for getting expected credentials."""
return
[
...
...
@@ -172,13 +173,11 @@ class TestProgramListing(
self
.
mock_credentials_api
(
self
.
student
,
data
=
self
.
CREDENTIALS_API_RESPONSE
,
reset_url
=
False
)
response
=
self
.
client
.
get
(
reverse
(
"program_listing_view"
))
self
.
assertEqual
(
response
.
status_code
,
200
)
for
certificate
in
self
.
_expected_credentials_data
():
self
.
assertContains
(
response
,
certificate
[
'display_name'
])
self
.
assertContains
(
response
,
certificate
[
'credential_url'
])
for
certificate
in
self
.
_expected_credetials_data
():
self
.
assertIn
(
certificate
[
'display_name'
],
response
.
content
)
self
.
assertIn
(
certificate
[
'credential_url'
],
response
.
content
)
self
.
assertIn
(
'images/xseries-certificate-visual.png'
,
response
.
content
)
self
.
assertContains
(
response
,
'images/xseries-certificate-visual.png'
)
@httpretty.activate
def
test_get_xseries_certificates_without_data
(
self
):
...
...
@@ -193,8 +192,6 @@ class TestProgramListing(
self
.
mock_credentials_api
(
self
.
student
,
data
=
{
"results"
:
[]},
reset_url
=
False
)
response
=
self
.
client
.
get
(
reverse
(
"program_listing_view"
))
self
.
assertEqual
(
response
.
status_code
,
200
)
for
certificate
in
self
.
_expected_credetials_data
():
self
.
assertNotIn
(
certificate
[
'display_name'
],
response
.
content
)
self
.
assertNotIn
(
certificate
[
'credential_url'
],
response
.
content
)
for
certificate
in
self
.
_expected_credentials_data
():
self
.
assertNotContains
(
response
,
certificate
[
'display_name'
])
self
.
assertNotContains
(
response
,
certificate
[
'credential_url'
])
openedx/core/djangoapps/programs/tests/factories.py
0 → 100644
View file @
0d27b5ed
"""Factories for generating fake program-related data."""
import
factory
from
factory.fuzzy
import
FuzzyText
class
Program
(
factory
.
Factory
):
"""
Factory for stubbing program resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
id
=
factory
.
Sequence
(
lambda
n
:
n
)
# pylint: disable=invalid-name
name
=
FuzzyText
(
prefix
=
'Program '
)
subtitle
=
FuzzyText
(
prefix
=
'Subtitle '
)
category
=
'xseries'
status
=
'unpublished'
marketing_slug
=
FuzzyText
(
prefix
=
'slug_'
)
organizations
=
[]
course_codes
=
[]
banner_image_urls
=
{}
class
Organization
(
factory
.
Factory
):
"""
Factory for stubbing nested organization resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
key
=
FuzzyText
(
prefix
=
'org_'
)
display_name
=
FuzzyText
(
prefix
=
'Display Name '
)
class
CourseCode
(
factory
.
Factory
):
"""
Factory for stubbing nested course code resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
display_name
=
FuzzyText
(
prefix
=
'Display Name '
)
run_modes
=
[]
class
RunMode
(
factory
.
Factory
):
"""
Factory for stubbing nested run mode resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
course_key
=
FuzzyText
(
prefix
=
'org/'
,
suffix
=
'/run'
)
mode_slug
=
'verified'
openedx/core/djangoapps/programs/tests/mixins.py
View file @
0d27b5ed
...
...
@@ -4,6 +4,7 @@ import json
import
httpretty
from
openedx.core.djangoapps.programs.models
import
ProgramsApiConfig
from
openedx.core.djangoapps.programs.tests
import
factories
class
ProgramsApiConfigMixin
(
object
):
...
...
@@ -50,176 +51,48 @@ class ProgramsDataMixin(object):
'organization-b/course-d/winter'
,
]
# TODO: Use factory-boy.
PROGRAMS_API_RESPONSE
=
{
'results'
:
[
{
'id'
:
1
,
'name'
:
PROGRAM_NAMES
[
0
],
'subtitle'
:
'A program used for testing purposes'
,
'category'
:
'xseries'
,
'status'
:
'unpublished'
,
'marketing_slug'
:
'{}_test_url'
.
format
(
PROGRAM_NAMES
[
0
]
.
replace
(
' '
,
'_'
)),
'organizations'
:
[
{
'display_name'
:
'Test Organization A'
,
'key'
:
'organization-a'
}
],
'course_codes'
:
[
{
'display_name'
:
'Test Course A'
,
'key'
:
'course-a'
,
'organization'
:
{
'display_name'
:
'Test Organization A'
,
'key'
:
'organization-a'
},
'run_modes'
:
[
{
'course_key'
:
COURSE_KEYS
[
0
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'fall'
},
{
'course_key'
:
COURSE_KEYS
[
1
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'winter'
}
]
},
{
'display_name'
:
'Test Course B'
,
'key'
:
'course-b'
,
'organization'
:
{
'display_name'
:
'Test Organization A'
,
'key'
:
'organization-a'
},
'run_modes'
:
[
{
'course_key'
:
COURSE_KEYS
[
2
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'fall'
},
{
'course_key'
:
COURSE_KEYS
[
3
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'winter'
}
]
}
],
'created'
:
'2015-10-26T17:52:32.861000Z'
,
'modified'
:
'2015-11-18T22:21:30.826365Z'
},
{
'id'
:
2
,
'name'
:
PROGRAM_NAMES
[
1
],
'subtitle'
:
'Another program used for testing purposes'
,
'category'
:
'xseries'
,
'status'
:
'unpublished'
,
'marketing_slug'
:
'{}_test_url'
.
format
(
PROGRAM_NAMES
[
1
]
.
replace
(
' '
,
'_'
)),
'organizations'
:
[
{
'display_name'
:
'Test Organization B'
,
'key'
:
'organization-b'
}
],
'course_codes'
:
[
{
'display_name'
:
'Test Course C'
,
'key'
:
'course-c'
,
'organization'
:
{
'display_name'
:
'Test Organization B'
,
'key'
:
'organization-b'
},
'run_modes'
:
[
{
'course_key'
:
COURSE_KEYS
[
4
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'fall'
},
{
'course_key'
:
COURSE_KEYS
[
5
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'winter'
}
]
},
{
'display_name'
:
'Test Course D'
,
'key'
:
'course-d'
,
'organization'
:
{
'display_name'
:
'Test Organization B'
,
'key'
:
'organization-b'
},
'run_modes'
:
[
{
'course_key'
:
COURSE_KEYS
[
6
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'fall'
},
{
'course_key'
:
COURSE_KEYS
[
7
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'winter'
}
]
}
],
'created'
:
'2015-10-26T19:59:03.064000Z'
,
'modified'
:
'2015-10-26T19:59:18.536000Z'
},
{
'id'
:
3
,
'name'
:
PROGRAM_NAMES
[
2
],
'subtitle'
:
'A third program used for testing purposes'
,
'category'
:
'xseries'
,
'status'
:
'unpublished'
,
'marketing_slug'
:
'{}_test_url'
.
format
(
PROGRAM_NAMES
[
2
]
.
replace
(
' '
,
'_'
)),
'organizations'
:
[
{
'display_name'
:
'Test Organization B'
,
'key'
:
'organization-b'
}
],
'course_codes'
:
[
{
'display_name'
:
'Test Course D'
,
'key'
:
'course-d'
,
'organization'
:
{
'display_name'
:
'Test Organization B'
,
'key'
:
'organization-b'
},
'run_modes'
:
[
{
'course_key'
:
COURSE_KEYS
[
7
],
'mode_slug'
:
'verified'
,
'sku'
:
''
,
'start_date'
:
'2015-11-05T07:39:02.791741Z'
,
'run_key'
:
'winter'
}
]
}
],
'created'
:
'2015-10-26T19:59:03.064000Z'
,
'modified'
:
'2015-10-26T19:59:18.536000Z'
}
factories
.
Program
(
id
=
1
,
name
=
PROGRAM_NAMES
[
0
],
organizations
=
[
factories
.
Organization
()],
course_codes
=
[
factories
.
CourseCode
(
run_modes
=
[
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
0
]),
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
1
]),
]),
factories
.
CourseCode
(
run_modes
=
[
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
2
]),
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
3
]),
]),
]
),
factories
.
Program
(
id
=
2
,
name
=
PROGRAM_NAMES
[
1
],
organizations
=
[
factories
.
Organization
()],
course_codes
=
[
factories
.
CourseCode
(
run_modes
=
[
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
4
]),
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
5
]),
]),
factories
.
CourseCode
(
run_modes
=
[
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
6
]),
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
7
]),
]),
]
),
factories
.
Program
(
id
=
3
,
name
=
PROGRAM_NAMES
[
2
],
organizations
=
[
factories
.
Organization
()],
course_codes
=
[
factories
.
CourseCode
(
run_modes
=
[
factories
.
RunMode
(
course_key
=
COURSE_KEYS
[
7
]),
]),
]
),
]
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment