6.4 KiB
Code Context
Files Retrieved
List with exact line ranges:
app/test/firehose_web/controllers/blog_test.exs(lines 1-128) - Comprehensive blog controller tests covering HTML and JSON API endpoints for engineering blog and release notesapp/lib/firehose_web/controllers/blog_controller.ex(lines 1-79) - Blog controller with pagination, 404 handling, and input validationapp/test/support/conn_case.ex(lines 1-38) - Test case template for connection testsapp/lib/firehose/blogs/engineering_blog.ex(lines 1-7) - Engineering blog module configurationapp/lib/firehose/blogs/release_notes.ex(lines 1-7) - Release notes blog module configuration
Key Code
Test Organization
# Current structure has 4 describe blocks:
describe "engineering blog (HTML)" # 3 tests
describe "input validation" # 5 tests (newly added in last commit)
describe "release notes blog (HTML)" # 2 tests
describe "engineering blog (JSON API)" # 4 tests
describe "release notes blog (JSON API)" # 3 tests
Input Validation Logic (blog_controller.ex, lines 68-76)
defp parse_page(nil), do: 1
defp parse_page(str) do
case Integer.parse(str) do
{page, ""} when page > 0 -> page
_ -> 1
end
end
Test Coverage Added in Last Commit
describe "input validation" do
test "GET /blog/nonexistent returns 404", %{conn: conn} do
conn = get(conn, "/blog/nonexistent")
assert html_response(conn, 404)
end
test "GET /blog/engineering?page=abc falls back to page 1", %{conn: conn} do
conn = get(conn, "/blog/engineering?page=abc")
assert html_response(conn, 200) =~ "Engineering Blog"
end
test "GET /blog/engineering?page=-1 falls back to page 1", %{conn: conn} do
conn = get(conn, "/blog/engineering?page=-1")
assert html_response(conn, 200) =~ "Engineering Blog"
end
test "GET /blog/engineering?page=0 falls back to page 1", %{conn: conn} do
conn = get(conn, "/blog/engineering?page=0")
assert html_response(conn, 200) =~ "Engineering Blog"
end
test "GET /blog/engineering/nonexistent-post returns 404", %{conn: conn} do
assert_raise Blogex.NotFoundError, fn ->
get(conn, "/blog/engineering/nonexistent-post")
end
end
end
Architecture
The application uses:
- Blogex library for blog functionality (engineering blog and release notes)
- Phoenix framework for web endpoints
- ConnCase test helper for connection testing
- Two blog types:
Firehose.EngineeringBlogandFirehose.ReleaseNotes - Pagination through
blog.paginate(page)method - 404 handling via
Blogex.NotFoundErrorexception
Start Here
Which file to look at first and why:
Start with app/lib/firehose_web/controllers/blog_controller.ex
Why: This is the central controller that handles all blog requests. Understanding its structure (especially the parse_page/1 function and resolve_blog/2 plug) provides context for why the validation tests were added and how input handling works across both HTML and JSON endpoints.
Code Smells & Refactoring Suggestions
Smell 1: Repetitive Validation Tests
Issue: Four tests for page parameter validation (page=abc, -1, 0, and valid values) are highly repetitive with identical assertions.
Refactoring Suggestion: Use parameterized tests or test helpers:
# Test helper approach
test_page_fallback("page=abc", "abc")
test_page_fallback("page=-1", "-1")
test_page_fallback("page=0", "0")
defp test_page_fallback(query_param, expected_page) do
conn = get(conn, "/blog/engineering?#{query_param}")
assert html_response(conn, 200) =~ "Engineering Blog"
end
Smell 2: Missing Negative Test Coverage
Issue: Tests don't verify what happens when invalid blog_id is provided (e.g., /blog/invalid-blog).
Refactoring Suggestion: Add test for unknown blog:
test "GET /blog/unknown returns 404", %{conn: conn} do
conn = get(conn, "/blog/unknown")
assert html_response(conn, 404)
end
Smell 3: Inconsistent Test Naming
Issue: Some tests use hyphenated slugs (v0-1-0), others use different formats. The naming doesn't clearly indicate what's being tested.
Refactoring Suggestion: Standardize naming:
# Instead of: "GET /blog/releases/v0-1-0 returns HTML post"
test "GET /blog/releases/:slug returns a release post", %{conn: conn} do
Smell 4: Redundant Layout Assertions
Issue: Multiple tests assert the same "firehose" string appears in response, testing layout presence.
Refactoring Suggestion: Create a shared test helper:
defp assert_has_app_layout(body),
do: assert body =~ "firehose"
# Then in tests: assert_has_app_layout(body)
Smell 5: Test Order Doesn't Follow Flow
Issue: Tests are grouped by endpoint but validation tests (which should be first for defensive programming) are in the middle.
Refactoring Suggestion: Reorder to follow natural request flow:
- Input validation (404s, invalid params)
- Success cases (index, show, tag)
- Edge cases (pagination, RSS feeds)
Smell 6: No Test for Controller-Level Error Handling
Issue: The controller uses halt() in the resolve_blog plug, but there's no test verifying this behavior.
Refactoring Suggestion: Add test:
test "GET /blog/:blog_id with invalid blog halts request", %{conn: conn} do
conn = get(conn, "/blog/invalid")
assert conn.halted
end
Smell 7: Mixed Response Types Without Clear Separation
Issue: HTML tests use html_response/2, JSON tests use json_response/2, but there's no helper to verify content type before parsing.
Refactoring Suggestion: Create response helpers:
defp assert_html(conn, status), do: assert html_response(conn, status) != ""
defp assert_json(conn, status), do: assert json_response(conn, status) != %{}
Smell 8: No Test for Concurrent Requests or Edge Cases
Issue: Missing tests for:
- Empty page parameter (
?page=) - Very large page numbers
- Special characters in slug/tag parameters
Refactoring Suggestion: Add edge case tests to validation describe block.
Overall Recommendations
- Extract test helpers to reduce duplication (especially for page validation)
- Standardize test naming conventions across all blog types
- Add positive test for valid page numbers (currently missing)
- Consider property-based testing for input validation scenarios
- Add performance tests if pagination is used heavily
- Create integration tests that verify end-to-end flows