Skip to content

Commit

Permalink
Merge pull request #229 from Divyesh000/incompletetests
Browse files Browse the repository at this point in the history
complete incomplete tests
  • Loading branch information
creme332 authored Jun 11, 2024
2 parents a0486f1 + 0296b46 commit 0215865
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 60 deletions.
12 changes: 5 additions & 7 deletions src/models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -276,19 +276,17 @@ public function getAverageRating(): float
-- get IDs of all clients who purchased current product
SELECT DISTINCT o.client_id
FROM `order` o
JOIN order_product op ON o.order_id = op.order_id
WHERE op.product_id = r.product_id
JOIN order_product op
ON o.order_id = op.order_id
AND op.product_id = r.product_id
)
EOL;

$params = ['product_id' => $this->product_id];

$result = $this->query($query, $params);
$result = $this->query($query, ['product_id' => $this->product_id]);

// Extract the average rating from the result array
if (!empty($result)) {
$averageRating = $result[0]->average_rating;
return $averageRating !== null ? round((float)$averageRating, 2) : 0; // Round to two decimal places
return (float)$result[0]->average_rating;
}

return 0; // No reviews, return 0 as the average rating
Expand Down
11 changes: 8 additions & 3 deletions tests/helpers/TestHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,17 @@ public static function createStore(bool $saveToDatabase = true): Store
* Create a review and saves it to database.
* @param Product $product A valid product already present in database
* @param Client $client A valid client already present in database
* @param int|null $rating Rating for review
* @param bool $verified Whether to create an order for client for given product.
* @return Review
* @throws Exception
*/
public static function createReview(Product $product, Client $client, bool $verified = false): Review
{
public static function createReview(
Product $product,
Client $client,
int $rating = null,
bool $verified = false
): Review {
if ($verified) {
// place an order for client and product

Expand Down Expand Up @@ -262,7 +267,7 @@ public static function createReview(Product $product, Client $client, bool $veri
product_id: $product->getProductID(),
client_id: $client->getUserID(),
text: self::$faker->sentence(10),
rating: self::$faker->numberBetween(1, 5)
rating: $rating ?? self::$faker->numberBetween(1, 5)
);

$success = $review->save();
Expand Down
184 changes: 149 additions & 35 deletions tests/models/ProductTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,53 +133,141 @@ public function testToArray(): void

public function testSave(): void
{
$this->markTestIncomplete(
'Use data providers here for at least 3 test cases, ...',
// Prepare test data
$newProductData = [
'name' => 'New Product',
'calories' => 100,
'img_url' => 'new_product.jpeg',
'img_alt_text' => 'New Product Image',
'category' => 'New Category',
'price' => 10.00,
'description' => 'New Product Description'
];

// Create a new product object with the test data
$newProduct = new Product(
$newProductData['name'],
$newProductData['calories'],
$newProductData['img_url'],
$newProductData['img_alt_text'],
$newProductData['category'],
$newProductData['price'],
$newProductData['description']
);

// Save the product to the database
$result = $newProduct->save();

// Assert that the product was saved successfully
$this->assertTrue($result);

// Fetch the saved product from the database
$savedProduct = Product::getByID($newProduct->getProductID());

// Assert that the saved product matches the test data
$this->assertEquals($newProductData['name'], $savedProduct->getName());
$this->assertEquals($newProductData['calories'], $savedProduct->getCalories());
$this->assertEquals($newProductData['img_url'], $savedProduct->getImgRelativePath());
$this->assertEquals($newProductData['img_alt_text'], $savedProduct->getImgAltText());
$this->assertEquals($newProductData['category'], $savedProduct->getCategory());
$this->assertEquals($newProductData['price'], $savedProduct->getPrice());
$this->assertEquals($newProductData['description'], $savedProduct->getDescription());
}


public function testValidate(): void
{
// Validate the dummy product
$errors = $this->dummy_product->validate();

// Check if there are no validation errors
$this->assertEmpty($errors);
// Prepare test data with invalid values
$invalidProductData = [
'name' => '', // Empty name
'calories' => -10, // Negative calories
'img_url' => 'invalid_image.txt', // Invalid image extension
'img_alt_text' => 'In', // Invalid image alt text length
'category' => '', // Empty category
'price' => 0, // Zero price
'description' => '' // Empty description
];

$this->markTestIncomplete(
'This test lacks test cases, ...',
// Create a new product object with the invalid test data
$invalidProduct = new Product(
$invalidProductData['name'],
$invalidProductData['calories'],
$invalidProductData['img_url'],
$invalidProductData['img_alt_text'],
$invalidProductData['category'],
$invalidProductData['price'],
$invalidProductData['description']
);

// Validate the product
$errors = $invalidProduct->validate();

// Assert that validation errors are present for each invalid field
$this->assertArrayHasKey('name', $errors);
$this->assertArrayHasKey('calories', $errors);
$this->assertArrayHasKey('img_url', $errors);
$this->assertArrayHasKey('img_alt_text', $errors);
$this->assertArrayHasKey('category', $errors);
$this->assertArrayHasKey('price', $errors);
$this->assertArrayHasKey('description', $errors);

// Assert that there are exactly 7 validation errors
$this->assertCount(7, $errors);
}


/**
* @throws Exception
*/
public function testGetRatingDistribution(): void
{
$distribution = $this->dummy_product->getRatingDistribution();
// reset data from setUp
self::resetDatabase();

// Check if the distribution contains the expected keys and values
// Here dummy product contains a single review:
$this->assertArrayHasKey($this->dummy_review->getRating(), $distribution);
$this->assertEquals(100.0, $distribution[$this->dummy_review->getRating()]);
// Create a new product for testing
$product = self::createProduct();
$this->dummy_client = self::createClient();

$this->markTestIncomplete(
'This test lacks test cases. This test might fail when getRatingDistribution excludes unverified reviews.',
);
// Create mock review data with different ratings
$verifiedReviewRatings = [5, 4, 3, 2, 1, 5, 4, 3, 4, 5];
// Insert mock review data into the database
foreach ($verifiedReviewRatings as $reviewData) {
self::createReview($product, $this->dummy_client, $reviewData, true);
}

// Create a random number of unverified reviews with different ratings
for ($i = 0; $i < self::$faker->numberBetween(0, 10); $i++) {
$rating = self::$faker->numberBetween(1, 5);
self::createReview($product, self::createClient(), $rating);
}

// Retrieve the rating distribution for the product
$ratingDistribution = $product->getRatingDistribution();

// Assert that the rating distribution is accurate
$expectedDistribution = [
1 => 10.0, // 1 star
2 => 10.0, // 2 stars
3 => 20.0, // 3 stars
4 => 30.0, // 4 stars
5 => 30.0, // 5 stars
];
$this->assertEquals($expectedDistribution, $ratingDistribution);
}

public function testDeleteProduct(): void
{
$product_id = $this->dummy_product->getProductID();
$result = $this->dummy_product->deleteProduct();

// Check if the product was deleted successfully
$this->assertTrue($result);

// Check if the product no longer exists in the database
$product = Product::getByID($product_id);
$this->assertNull($product);

$this->markTestIncomplete(
'This test lacks test cases, ...',
);
// Save the product to the database
$product = $this->dummy_product;

// Delete the product from the database
$success = $product->deleteProduct();
// Assert that the delete operation was successful
self::assertTrue($success);
// Try to retrieve the product by ID to check if it was deleted
$deletedProduct = Product::getByID($product->getProductID());
// Assert that the product is no longer in the database
self::assertNull($deletedProduct);
}

public function testUpdateProduct(): void
Expand Down Expand Up @@ -210,15 +298,41 @@ public function testUpdateProduct(): void
$this->assertEquals('Updated description', $updatedProduct->getDescription());
}

/**
* @throws Exception
*/
public function testGetAverageRating(): void
{
$averageRating = $this->dummy_product->getAverageRating();
// reset database as we don't want previously created reviews from setUp.
self::resetDatabase();

$this->assertNotEquals(999.0, $averageRating);
$this->dummy_product = self::createProduct();
$this->dummy_client = self::createClient();

$this->markTestIncomplete(
'This test lacks test cases, ...',
);
// Create a random number of verified reviews with different ratings
$verifiedReviewRatings = [];
for ($i = 0; $i < self::$faker->numberBetween(0, 10); $i++) {
$rating = self::$faker->numberBetween(1, 5);
$verifiedReviewRatings[] = $rating;
self::createReview($this->dummy_product, $this->dummy_client, $rating, true);
}

// Note: $this->dummy_client can be a verified reviewer do not write unverified reviews with it

// Create a random number of unverified reviews with different ratings
for ($i = 0; $i < self::$faker->numberBetween(0, 10); $i++) {
$rating = self::$faker->numberBetween(1, 5);
self::createReview($this->dummy_product, self::createClient(), $rating);
}

// Retrieve the average rating for the product
$averageRating = $this->dummy_product->getAverageRating();

// Assert that the average rating is accurate
$expectedAverageRating = count($verifiedReviewRatings) === 0 ? 0 : (float)array_sum(
$verifiedReviewRatings
) / count($verifiedReviewRatings);
$this->assertEqualsWithDelta($expectedAverageRating, $averageRating, 0.0001);
}

public function testGetReviews(): void
Expand Down
83 changes: 68 additions & 15 deletions tests/models/ReviewTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Steamy\Model\Review;
use Steamy\Model\Product;
use Steamy\Tests\helpers\TestHelper;
use Steamy\Model\Comment;
use Throwable;

final class ReviewTest extends TestCase
Expand Down Expand Up @@ -278,31 +279,83 @@ public function testSave(string $text, int $rating, DateTime $created_date, arra

public function testGetNestedComments(): void
{
$this->markTestIncomplete(
'This test lacks test cases, ...',
// Create a review
$review = new Review(
product_id: $this->dummy_product->getProductID(),
client_id: $this->reviewer->getUserID(),
text: "This is a test review for nested comments.",
rating: 4
);
$review->save();

$review = new Review(review_id: 1);
$comments = $review->getNestedComments();

$this->assertIsArray($comments);
foreach ($comments as $comment) {
$this->assertObjectHasAttribute('children', $comment);
if (!empty($comment->children)) {
foreach ($comment->children as $childComment) {
$this->assertObjectHasAttribute('children', $childComment);
}
}
}
// Create root level comment
$comment1 = new Comment(
review_id: $review->getReviewID(),
user_id: $this->reviewer->getUserID(),
text: "This is a root level comment."
);
$comment1->save();

// Create nested comments
$comment2 = new Comment(
review_id: $review->getReviewID(),
user_id: $this->reviewer->getUserID(),
text: "This is a child comment.",
parent_comment_id: $comment1->getCommentID()
);
$comment2->save();

$comment3 = new Comment(
review_id: $review->getReviewID(),
user_id: $this->reviewer->getUserID(),
text: "This is another root level comment."
);
$comment3->save();

$comment4 = new Comment(
review_id: $review->getReviewID(),
user_id: $this->reviewer->getUserID(),
text: "This is a child of a child comment.",
parent_comment_id: $comment2->getCommentID()
);
$comment4->save();

// Fetch nested comments
$nestedComments = $review->getNestedComments();

// Check if the structure is correct
$this->assertIsArray($nestedComments);
$this->assertCount(2, $nestedComments); // Should have 2 root level comments

// Verify the first root level comment
$this->assertEquals($comment1->getCommentID(), $nestedComments[0]->comment_id);
$this->assertCount(1, $nestedComments[0]->children); // Should have 1 child

// Verify the child comment of the first root level comment
$this->assertEquals($comment2->getCommentID(), $nestedComments[0]->children[0]->comment_id);
$this->assertCount(1, $nestedComments[0]->children[0]->children); // Should have 1 child

// Verify the child of the child comment
$this->assertEquals($comment4->getCommentID(), $nestedComments[0]->children[0]->children[0]->comment_id);
$this->assertCount(0, $nestedComments[0]->children[0]->children[0]->children); // Should have no children

// Verify the second root level comment
$this->assertEquals($comment3->getCommentID(), $nestedComments[1]->comment_id);
$this->assertCount(0, $nestedComments[1]->children); // Should have no children
}


/**
* @throws Exception
*/
public function testIsVerified(): void
{
// note: do not use data provider here because $faker is static and causes a bug
$verified_review = self::createReview(self::createProduct(), self::createClient(), true);
$verified_review = self::createReview(
self::createProduct(),
self::createClient(),
verified: true
);
$unverified_review = self::createReview(self::createProduct(), self::createClient());
$fake_review = new Review(review_id: -321, product_id: -32);

Expand Down

0 comments on commit 0215865

Please sign in to comment.