Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e5df192

Browse files
committedFeb 14, 2022
Fix merge conflict with master
2 parents 1bbe817 + fb0aa0b commit e5df192

12 files changed

+468
-765
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.vscode/
22
.DS_Store
3+
.vscode
34

45
# GitHub's boilerplate Python gitignore
56
# https://github.com/github/gitignore/blob/master/Python.gitignore

‎Dockerfile

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ ADD $SUBMISSION_SUBFOLDER /app
2929

3030
# Overwrite files in student fork with upstream files
3131
ADD test.sh /app
32-
ADD tests /app/tests
3332

3433
# User defined requirements
3534
# RUN make init

‎README.md

+58-24
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ Summary of one-time project setup:
8181

8282
## Project Development Workflow
8383

84+
We will use a Test Driven Development programming workflow to work on this project. Notice the Red-Green-Refactor steps in the workflow steps outlined below.
85+
8486
1. When you want to begin work on this project, ensure that your virtual environment is activated:
8587

8688
```bash
@@ -89,54 +91,69 @@ $ source venv/bin/activate
8991

9092
2. Find the test file that contains the test you want to run. Ensure that the test(s) you want to run isn't skipped.
9193

92-
- Check the `tests` folder, and find the test file you want to run
94+
- Check the `tests` folder, and find the test file you want to run
9395
- In that test file, read through each test case
94-
- Remove all lines that contain `@pytest.mark.skip()`
96+
- If it is incomplete, complete the test.
97+
- *Is this a nominal or edge case?*
98+
- *What type of input do we need to test this case?*
99+
- *What is the expected output for the given input?*
100+
- Remove the lines that contain `@pytest.mark.skip()` for the test(s) you want to run.
95101

96-
3. Run the tests!
102+
3. Run the test(s)! (RED)
103+
- *See the [Details About How to Run Tests](#details-about-how-to-run-tests) section below for more information on how to run test(s).*
97104

98105
```bash
99-
# Must be in activated virtual environment
106+
# Must be in activated virtual environment in the project-root directory
100107
$ pytest
101108
```
102109

103-
4. Focus on the top test failure. Read through the test failure, and understand why the failure is happening. Confirm your findings with a classmate.
110+
4. Focus on the top test failure. Read through the test failure, and understand why the failure is happening. Confirm your findings with a classmate.
111+
- If it is a test you wrote, consider whether you are actually testing what you intend to test. Does the test need modification?
112+
104113

105-
5. Make a plan to fix the test failure.
114+
5. Make a plan to implement code to pass the test.
106115

107-
6. Write code to fix the test failure.
116+
6. Write code in `party.py` to pass the test.
108117

109118
7. Re-run the tests.
110119

111-
8. Repeat steps 5-7 until that test passes!
120+
8. Repeat steps 4-7 until that test passes! (GREEN)
112121

113-
9. Repeats steps 4-8 until you have finished all tests in the file.
122+
9. Repeats steps 3-8 until you have finished all tests in the file.
114123

115-
10. Begin using the test file of the next wave!
124+
10. Consider looking for opportunities to improve your code (REFACTOR)
116125

117-
11. When you are finished working for the day, deactivate your environment with deactivate or closing the Terminal tab/window
126+
11. Begin using the test file of the next wave!
127+
128+
12. When you are finished working for the day, deactivate your environment with deactivate or closing the Terminal tab/window
118129

119130
```bash
120131
$ deactivate
121132
```
122133

134+
Finally, at submission time, **no matter where you are**, submit the project via Learn.
135+
136+
This will let us give feedback on what you've finished so that you can be better prepared for the next project.
137+
123138
## Details About How to Run Tests
124139

125-
Run all unskipped tests that exist in this project with:
140+
All the commands described below should be run from the project-root directory `viewing-party`. Note that the project-root directory is the repository `viewing-party`. It is distinct from the directory `viewing_party` that contains the source code in `party.py`.
141+
142+
To run all unskipped tests that exist in this project with:
126143

127144
```bash
128145
# Must be in activated virtual environment
129146
$ pytest
130147
```
131148

132-
If you want to see any `print` statements print to the console, add `-s` to the end of any `pytest` command:
149+
To see any `print` statements print to the console, add `-s` to the end of any `pytest` command:
133150

134151
```bash
135152
# Must be in activated virtual environment
136153
$ pytest -s
137154
```
138155

139-
If you want to run all unskipped tests that exist in one file, use:
156+
To run all unskipped tests that exist in one file, use:
140157

141158
```bash
142159
# Must be in activated virtual environment
@@ -145,19 +162,33 @@ $ pytest tests/test_file_name.py
145162

146163
... where `test_file_name.py` is replaced with the correct test file name.
147164

148-
## Project Write-Up: How to Complete and Submit
165+
To run a single test by name:
149166

150-
The goal of this project is to write code in `party.py` so that as many of the tests pass as possible.
167+
```bash
168+
# Must be in activated virtual environment
169+
$ pytest tests/test_file_name.py::test_name
170+
```
151171

152-
To complete this project, use the above workflow and follow these steps:
172+
... where `test_name.py` is relpaced with the name of the function.
153173

154-
1. Start with making the tests in `test_wave_01.py` pass.
155-
1. Review your code in `party.py` and see if there are ways you can make the code more readable.
156-
1. Then, work on making the tests in `test_wave_02.py` pass.
157-
1. Review your code in `party.py`
158-
1. Repeat on all test files until submission time.
174+
## Play Testing
159175

160-
At submission time, no matter where you are, submit the project via Learn.
176+
While we will mainly use a Test Driven Development (TDD) workflow for this project, it can be helpful to run code independently from running tests. To do this, a file `play_tester.py` is provided.
177+
178+
To run this file, use:
179+
180+
```bash
181+
# Must be in activated virtual environment in the project root-directory
182+
python3 play_tester.py
183+
```
184+
185+
There is some starter code provided in `play_tester.py`. This code prints the test data that is used for many of the tests. Looking closely at this data can help us think critically about the expected output for given input for each function. Then, calling each function with this data allows us to observe the **actual** output for given input.
186+
187+
## Test Data
188+
189+
We will note that much of the test data for this project is provided by the file `test_constants.py`. As test data gets more and more complex, it is helpful to organize this data in its own file to enhance consistency and readability. Pytest, like many testing libraries, provide a special too for test data called **fixtures**. We will learn about fixtures later in the curriculum.
190+
191+
For the time being, we need to make sure that the data provided to each test is clean and free of any changes that running another test may have introduced. Recall the *Modifying Mutable Objects* section of the *Variables Are References lesson.* To ensure that the data for each test is storied in a unique place in memory, there are functions implemented in `test_constants.py` that provide clean test data (i.e. `clean_wave_3_data`) by using `copy.deepcopy`.
161192

162193
## Project Directions
163194

@@ -178,7 +209,7 @@ In `party.py`, there should be a function named `create_movie`. This function sh
178209
- The values of these key-value pairs should be appropriate values
179210
- If `title` is falsy, `genre` is falsy, or `rating` is falsy, this function should return `None`
180211

181-
2. The next two tests are about an `add_to_watched()` function.
212+
2. The next two tests are about the `add_to_watched()` function.
182213

183214
In `party.py`, there should be a function named `add_to_watched`. This function should...
184215

@@ -230,6 +261,8 @@ In `party.py`, there should be a function named `watch_movie`. This function sho
230261
- If the title is not a movie in the user's watchlist:
231262
- return the `user_data`
232263

264+
Note: For Waves 2, 3, 4, and 5, your implementation of each of the functions should not modify `user_data`.
265+
233266
### Wave 2
234267

235268
1. The first two tests are about a `get_watched_avg_rating()` function.
@@ -253,6 +286,7 @@ In `party.py`, there should be a function named `get_most_watched_genre`. This f
253286
- The values of `"genre"` is a string.
254287
- Determine which genre is most frequently occurring in the watched list
255288
- return the genre that is the most frequently watched
289+
- If the value of "watched" is an empty list, `get_most_watched_genre` should return `None`.
256290

257291
### Wave 3
258292

‎play_tester.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# import source code
2+
from viewing_party.party import *
3+
4+
# import test data
5+
from tests.test_constants import *
6+
7+
# import "pretty-print" library
8+
import pprint
9+
pp = pprint.PrettyPrinter(indent=4)
10+
11+
# play testing section
12+
print("\n-----Wave 01 test data-----")
13+
pp.pprint(HORROR_1)
14+
pp.pprint(FANTASY_1)
15+
pp.pprint(FANTASY_2)
16+
17+
# print("\n-----Wave 02 user_data-----")
18+
# pp.pprint(clean_wave_2_data())
19+
20+
#print("\n-----Wave 03 user_data-----")
21+
#pp.pprint(clean_wave_3_data())
22+
23+
# Wave 04 user data
24+
#print("\n-----Wave 04 user_data-----")
25+
#pp.pprint(clean_wave_4_data())
26+
27+
# Wave 05 user data
28+
#print("\n-----Wave 05 user_data-----")
29+
#pp.pprint(clean_wave_5_data())

‎requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ attrs==20.3.0
22
iniconfig==1.1.1
33
packaging==20.8
44
pluggy==0.13.1
5+
pprintpp==0.4.0
56
py==1.10.0
67
pyparsing==2.4.7
78
pytest==6.2.1

‎tests/test_constants.py

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import copy
2+
3+
# ********************************
4+
# *** Do Not Modify This File ****
5+
# ********************************
6+
7+
# Data for Unit Tests
8+
9+
#----------WAVE01-------------
10+
MOVIE_TITLE_1 = "It Came from the Stack Trace"
11+
GENRE_1 = "Horror"
12+
RATING_1 = 3.5
13+
14+
#----------WAVE02-------------
15+
HORROR_1 = {
16+
"title": MOVIE_TITLE_1,
17+
"genre": GENRE_1,
18+
"rating": RATING_1
19+
}
20+
FANTASY_1 = {
21+
"title": "The Lord of the Functions: The Fellowship of the Function",
22+
"genre": "Fantasy",
23+
"rating": 4.8
24+
}
25+
FANTASY_2 = {
26+
"title": "The Lord of the Functions: The Two Parameters",
27+
"genre": "Fantasy",
28+
"rating": 4.0
29+
}
30+
FANTASY_3 = {
31+
"title": "The Lord of the Functions: The Return of the Value",
32+
"genre": "Fantasy",
33+
"rating": 4.0
34+
}
35+
FANTASY_4 = {
36+
"title": "The Programmer: An Unexpected Stack Trace",
37+
"genre": "Fantasy",
38+
"rating": 4.0
39+
}
40+
ACTION_1 = {
41+
"title": "The JavaScript and the React",
42+
"genre": "Action",
43+
"rating": 2.2
44+
}
45+
ACTION_2 = {
46+
"title": "2 JavaScript 2 React",
47+
"genre": "Action",
48+
"rating": 4.2
49+
}
50+
ACTION_3 = {
51+
"title": "JavaScript 3: VS Code Lint",
52+
"genre": "Action",
53+
"rating": 3.5
54+
}
55+
INTRIGUE_1 = {
56+
"title": "Recursion",
57+
"genre": "Intrigue",
58+
"rating": 2.0
59+
}
60+
INTRIGUE_2 = {
61+
"title": "Instructor Student TA Manager",
62+
"genre": "Intrigue",
63+
"rating": 4.5
64+
}
65+
INTRIGUE_3 = {
66+
"title": "Zero Dark Python",
67+
"genre": "Intrigue",
68+
"rating": 3.0
69+
}
70+
USER_DATA_2 = {
71+
"watched": [
72+
FANTASY_1,
73+
FANTASY_2,
74+
FANTASY_3,
75+
ACTION_1,
76+
INTRIGUE_1,
77+
INTRIGUE_2
78+
],
79+
}
80+
81+
#-----WAVE 3--------
82+
USER_DATA_3 = copy.deepcopy(USER_DATA_2)
83+
USER_DATA_3["friends"] = [
84+
{
85+
"watched": [
86+
FANTASY_1,
87+
FANTASY_3,
88+
FANTASY_4,
89+
HORROR_1,
90+
]
91+
},
92+
{
93+
"watched": [
94+
FANTASY_1,
95+
ACTION_1,
96+
INTRIGUE_1,
97+
INTRIGUE_3,
98+
]
99+
}
100+
]
101+
102+
#-----WAVE 4--------
103+
104+
HORROR_1b = copy.deepcopy(HORROR_1)
105+
FANTASY_1b = copy.deepcopy(FANTASY_1)
106+
FANTASY_2b = copy.deepcopy(FANTASY_2)
107+
FANTASY_3b = copy.deepcopy(FANTASY_3)
108+
FANTASY_4b = copy.deepcopy(FANTASY_4)
109+
ACTION_1b = copy.deepcopy(ACTION_1)
110+
ACTION_2b = copy.deepcopy(ACTION_2)
111+
ACTION_3b = copy.deepcopy(ACTION_3)
112+
INTRIGUE_1b = copy.deepcopy(INTRIGUE_1)
113+
INTRIGUE_2b = copy.deepcopy(INTRIGUE_2)
114+
INTRIGUE_3b = copy.deepcopy(INTRIGUE_3)
115+
116+
HORROR_1b["host"] = "netflix"
117+
FANTASY_1b["host"] = "netflix"
118+
FANTASY_2b["host"] = "netflix"
119+
FANTASY_3b["host"] = "amazon"
120+
FANTASY_4b["host"] = "hulu"
121+
ACTION_1b["host"] = "amazon"
122+
ACTION_2b["host"] = "amazon"
123+
ACTION_3b["host"] = "hulu"
124+
INTRIGUE_1b["host"] = "hulu"
125+
INTRIGUE_2b["host"] = "disney+"
126+
INTRIGUE_3b["host"] = "disney+"
127+
128+
USER_DATA_4 = {
129+
"watched": [
130+
FANTASY_1b,
131+
FANTASY_2b,
132+
FANTASY_3b,
133+
ACTION_1b,
134+
INTRIGUE_1b,
135+
INTRIGUE_2b
136+
],
137+
"friends": [
138+
{
139+
"watched": [
140+
FANTASY_1b,
141+
FANTASY_3b,
142+
FANTASY_4b,
143+
HORROR_1b,
144+
]
145+
},
146+
{
147+
"watched": [
148+
FANTASY_1b,
149+
ACTION_1b,
150+
INTRIGUE_1b,
151+
INTRIGUE_3b,
152+
]
153+
}
154+
]
155+
}
156+
157+
USER_DATA_4["subscriptions"] = ["netflix", "hulu"]
158+
159+
160+
#----WAVE 5-----------
161+
162+
USER_DATA_5 = copy.deepcopy(USER_DATA_4)
163+
164+
USER_DATA_5["favorites"] = [
165+
FANTASY_1b,
166+
FANTASY_2b,
167+
INTRIGUE_1b,
168+
INTRIGUE_2b
169+
]
170+
171+
#----Functions that return clean data for each test----
172+
173+
def clean_wave_2_data():
174+
return copy.deepcopy(USER_DATA_2)
175+
176+
def clean_wave_3_data():
177+
return copy.deepcopy(USER_DATA_3)
178+
179+
def clean_wave_4_data():
180+
return copy.deepcopy(USER_DATA_4)
181+
182+
def clean_wave_5_data():
183+
return copy.deepcopy(USER_DATA_5)

0 commit comments

Comments
 (0)
Please sign in to comment.