alpine
pycharm
โІ
+
+
--
xcode
https
saml
+
+
+
+
+
mxnet
=>
clickhouse
+
k8s
+
soap
+
jax
+
r
=
express
julia
+
cassandra
jax
+
ray
objc
+
+
matplotlib
+
ada
+
play
gatsby
+
svelte
android
+
termux
+
mxnet
c#
+
+
+
+
mxnet
โˆž
+
+
+
+
ractive
+
+
redis
jax
+
+
+
+
mxnet
+
saml
::
+
โ‰ 
+
adonis
+
+
+
+
koa
hack
julia
+
+
actix
ractive
fastapi
jest
Back to Blog
๐Ÿงช Setting Up Package Testing Framework: Simple Guide
Alpine Linux APK Testing

๐Ÿงช Setting Up Package Testing Framework: Simple Guide

Published Jun 4, 2025

Easy tutorial for creating a package testing framework in Alpine Linux. Perfect for beginners with step-by-step instructions and automated testing examples.

11 min read
0 views
Table of Contents

๐Ÿงช Setting Up Package Testing Framework: Simple Guide

Want to ensure packages work correctly before deployment? This guide shows you how to build a testing framework! ๐Ÿ˜Š Weโ€™ll create automated tests that verify package functionality and catch issues early. ๐Ÿ’ป

๐Ÿค” What is Package Testing?

Package testing verifies that software packages install correctly, function properly, and donโ€™t break existing systems. Think of it like quality control for your software!

Package testing helps with:

  • ๐Ÿ“ Catching installation problems early
  • ๐Ÿ”ง Verifying package dependencies work
  • ๐Ÿ’ก Ensuring system stability

๐ŸŽฏ What You Need

Before we start, you need:

  • โœ… Alpine Linux system with development tools
  • โœ… Root access for testing environments
  • โœ… Basic scripting knowledge
  • โœ… Sufficient disk space for test containers

๐Ÿ“‹ Step 1: Create Testing Environment

Set Up Isolated Test Environment

Letโ€™s create a safe testing environment! ๐Ÿ˜Š

What weโ€™re doing: Building isolated environments for package testing.

# Install testing tools
apk add docker lxc bash coreutils

# Create testing directory structure
mkdir -p /opt/package-testing/{tests,results,logs,containers}
cd /opt/package-testing

# Create base testing framework
cat > test-framework.sh << 'EOF'
#!/bin/bash

# Alpine Package Testing Framework
# ===============================

TEST_DIR="/opt/package-testing"
LOG_DIR="$TEST_DIR/logs"
RESULTS_DIR="$TEST_DIR/results"
CONTAINER_DIR="$TEST_DIR/containers"

# Initialize testing environment
init_testing() {
    echo "๐Ÿงช Initializing Package Testing Framework"
    
    mkdir -p "$LOG_DIR" "$RESULTS_DIR" "$CONTAINER_DIR"
    
    # Create test container template
    cat > "$CONTAINER_DIR/test-template.dockerfile" << 'DOCKER_EOF'
FROM alpine:latest
RUN apk update && apk add --no-cache bash curl
WORKDIR /test
COPY . /test/
DOCKER_EOF
    
    echo "โœ… Testing framework initialized"
}

# Test package installation
test_package_install() {
    local package_name="$1"
    local test_id="$(date +%Y%m%d_%H%M%S)_${package_name}"
    
    echo "๐Ÿ“ฆ Testing package: $package_name"
    
    # Create test container
    docker build -t "test-$test_id" "$CONTAINER_DIR" -f "$CONTAINER_DIR/test-template.dockerfile"
    
    # Test installation
    if docker run --rm "test-$test_id" sh -c "apk add --no-cache $package_name"; then
        echo "โœ… Package $package_name: Installation OK"
        echo "$package_name,PASS,$(date)" >> "$RESULTS_DIR/test-results.csv"
        return 0
    else
        echo "โŒ Package $package_name: Installation FAILED"
        echo "$package_name,FAIL,$(date)" >> "$RESULTS_DIR/test-results.csv"
        return 1
    fi
}

# Run test suite
run_test_suite() {
    local packages=("$@")
    local passed=0
    local failed=0
    
    echo "๐Ÿš€ Running test suite for ${#packages[@]} packages"
    
    for package in "${packages[@]}"; do
        if test_package_install "$package"; then
            ((passed++))
        else
            ((failed++))
        fi
    done
    
    echo "๐Ÿ“Š Test Results: $passed passed, $failed failed"
}

# Main function
case "$1" in
    init)
        init_testing
        ;;
    test)
        shift
        test_package_install "$@"
        ;;
    suite)
        shift
        run_test_suite "$@"
        ;;
    *)
        echo "Usage: $0 {init|test <package>|suite <packages...>}"
        ;;
esac
EOF

chmod +x test-framework.sh

# Initialize framework
./test-framework.sh init

What this does: ๐Ÿ“– Creates a complete package testing infrastructure.

Example output:

๐Ÿงช Initializing Package Testing Framework
โœ… Testing framework initialized
Testing directory structure created
โœ… Framework ready for testing

What this means: You have a professional testing setup! โœ…

๐Ÿ’ก Important Tips

Tip: Always test in isolated environments to avoid system damage! ๐Ÿ’ก

Warning: Some tests may require network access or special permissions! โš ๏ธ

๐Ÿ› ๏ธ Step 2: Create Comprehensive Test Cases

Build Advanced Testing Scripts

Time to create sophisticated test cases! ๐Ÿ˜Š

What weโ€™re doing: Building comprehensive test scripts for different scenarios.

# Create advanced testing script
cat > /opt/package-testing/advanced-tests.sh << 'EOF'
#!/bin/bash

# Advanced Package Testing Suite
# =============================

source /opt/package-testing/test-framework.sh

# Test package dependencies
test_package_dependencies() {
    local package="$1"
    local test_id="deps_$(date +%s)"
    
    echo "๐Ÿ”— Testing dependencies for: $package"
    
    # Create dependency test
    cat > "/tmp/test-deps-$test_id.sh" << 'TEST_EOF'
#!/bin/bash
apk update
echo "Installing package with dependency checking..."
apk add --no-cache --simulate "$1" 2>&1 | grep -E "(ERROR|CONFLICT|broken)" && exit 1
apk add --no-cache "$1"
echo "Verifying package is properly installed..."
apk info -e "$1" || exit 1
echo "Testing package can be removed cleanly..."
apk del "$1"
echo "Dependencies test passed!"
TEST_EOF
    
    chmod +x "/tmp/test-deps-$test_id.sh"
    
    if docker run --rm -v "/tmp/test-deps-$test_id.sh:/test.sh" alpine:latest /test.sh "$package"; then
        echo "โœ… Dependencies test passed for $package"
        rm -f "/tmp/test-deps-$test_id.sh"
        return 0
    else
        echo "โŒ Dependencies test failed for $package"
        rm -f "/tmp/test-deps-$test_id.sh"
        return 1
    fi
}

# Test package functionality
test_package_functionality() {
    local package="$1"
    local test_command="$2"
    
    echo "โš™๏ธ Testing functionality for: $package"
    
    # Create functionality test
    local test_script="/tmp/func-test-$(date +%s).sh"
    cat > "$test_script" << TEST_EOF
#!/bin/bash
apk update
apk add --no-cache $package
echo "Testing package functionality..."
$test_command
echo "Functionality test completed!"
TEST_EOF
    
    chmod +x "$test_script"
    
    if docker run --rm -v "$test_script:/test.sh" alpine:latest /test.sh; then
        echo "โœ… Functionality test passed for $package"
        rm -f "$test_script"
        return 0
    else
        echo "โŒ Functionality test failed for $package"
        rm -f "$test_script"
        return 1
    fi
}

# Test package security
test_package_security() {
    local package="$1"
    
    echo "๐Ÿ”’ Testing security for: $package"
    
    # Check for known vulnerabilities
    local vuln_check="/tmp/security-check-$(date +%s).sh"
    cat > "$vuln_check" << 'SEC_EOF'
#!/bin/bash
apk update
apk add --no-cache "$1"

# Check for setuid binaries
echo "Checking for setuid binaries..."
find /usr -perm -4000 -type f 2>/dev/null | head -5

# Check package files
echo "Checking package file permissions..."
apk info -L "$1" | head -10 | xargs ls -la 2>/dev/null | head -5

echo "Security check completed!"
SEC_EOF
    
    chmod +x "$vuln_check"
    
    if docker run --rm -v "$vuln_check:/test.sh" alpine:latest /test.sh "$package"; then
        echo "โœ… Security test passed for $package"
        rm -f "$vuln_check"
        return 0
    else
        echo "โš ๏ธ Security test completed with warnings for $package"
        rm -f "$vuln_check"
        return 1
    fi
}

# Performance testing
test_package_performance() {
    local package="$1"
    local performance_test="$2"
    
    echo "โšก Testing performance for: $package"
    
    local perf_script="/tmp/perf-test-$(date +%s).sh"
    cat > "$perf_script" << PERF_EOF
#!/bin/bash
apk update
echo "Installing $package..."
time apk add --no-cache $package

echo "Running performance test..."
time $performance_test

echo "Performance test completed!"
PERF_EOF
    
    chmod +x "$perf_script"
    
    if docker run --rm -v "$perf_script:/test.sh" alpine:latest /test.sh; then
        echo "โœ… Performance test completed for $package"
        rm -f "$perf_script"
        return 0
    else
        echo "โŒ Performance test failed for $package"
        rm -f "$perf_script"
        return 1
    fi
}

# Generate test report
generate_test_report() {
    local report_file="/opt/package-testing/results/test-report-$(date +%Y%m%d).html"
    
    cat > "$report_file" << 'HTML_EOF'
<!DOCTYPE html>
<html>
<head>
    <title>Package Testing Report</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .pass { color: green; }
        .fail { color: red; }
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
        th { background-color: #f2f2f2; }
    </style>
</head>
<body>
    <h1>๐Ÿงช Package Testing Report</h1>
    <p>Generated on: $(date)</p>
    
    <h2>Test Results Summary</h2>
    <table>
        <tr><th>Package</th><th>Status</th><th>Timestamp</th></tr>
HTML_EOF
    
    # Add test results from CSV
    if [ -f "/opt/package-testing/results/test-results.csv" ]; then
        while IFS=',' read -r package status timestamp; do
            if [ "$status" = "PASS" ]; then
                echo "        <tr><td>$package</td><td class=\"pass\">โœ… $status</td><td>$timestamp</td></tr>" >> "$report_file"
            else
                echo "        <tr><td>$package</td><td class=\"fail\">โŒ $status</td><td>$timestamp</td></tr>" >> "$report_file"
            fi
        done < "/opt/package-testing/results/test-results.csv"
    fi
    
    cat >> "$report_file" << 'HTML_EOF'
    </table>
    
    <h2>Test Environment</h2>
    <ul>
        <li>Alpine Linux Version: $(cat /etc/alpine-release)</li>
        <li>Docker Version: $(docker --version)</li>
        <li>Test Framework Version: 1.0</li>
    </ul>
</body>
</html>
HTML_EOF
    
    echo "๐Ÿ“Š Test report generated: $report_file"
}

# Main advanced testing menu
case "$1" in
    deps)
        test_package_dependencies "$2"
        ;;
    func)
        test_package_functionality "$2" "$3"
        ;;
    security)
        test_package_security "$2"
        ;;
    performance)
        test_package_performance "$2" "$3"
        ;;
    report)
        generate_test_report
        ;;
    full)
        echo "๐Ÿš€ Running full test suite for: $2"
        test_package_dependencies "$2"
        test_package_functionality "$2" "${3:-echo 'No functionality test specified'}"
        test_package_security "$2"
        test_package_performance "$2" "${4:-echo 'Basic performance test'}"
        generate_test_report
        ;;
    *)
        echo "Usage: $0 {deps|func|security|performance|report|full} <package> [test_command] [perf_test]"
        ;;
esac
EOF

chmod +x /opt/package-testing/advanced-tests.sh

# Test the advanced framework
echo "๐Ÿงช Testing the testing framework..."
/opt/package-testing/advanced-tests.sh deps curl

Code explanation:

  • Creates modular testing components
  • Tests dependencies, functionality, security, and performance
  • Generates HTML reports for results

Expected Output:

๐Ÿ”— Testing dependencies for: curl
โœ… Dependencies test passed for curl
๐Ÿงช Advanced testing framework ready

What this means: You have comprehensive testing capabilities! ๐ŸŽ‰

๐Ÿ”ง Step 3: Automate Testing Workflows

Create Continuous Testing Pipeline

Letโ€™s set up automated testing workflows! This is powerful! ๐ŸŽฏ

What weโ€™re doing: Building automated testing pipelines with scheduling.

# Create automated testing pipeline
cat > /opt/package-testing/automated-pipeline.sh << 'EOF'
#!/bin/bash

# Automated Package Testing Pipeline
# =================================

PIPELINE_DIR="/opt/package-testing"
CONFIG_FILE="$PIPELINE_DIR/pipeline-config.conf"

# Create configuration file
cat > "$CONFIG_FILE" << 'CONF_EOF'
# Package Testing Pipeline Configuration
PACKAGES_TO_TEST="curl wget git vim nano"
TEST_SCHEDULE="daily"
NOTIFICATION_EMAIL="[email protected]"
SLACK_WEBHOOK=""
TEST_TYPES="deps func security"
REPORT_FORMAT="html"
CONF_EOF

# Load configuration
source "$CONFIG_FILE"

# Send notifications
send_notification() {
    local message="$1"
    local status="$2"
    
    echo "๐Ÿ“ง Sending notification: $message"
    
    # Email notification (if configured)
    if [ -n "$NOTIFICATION_EMAIL" ] && command -v mail >/dev/null; then
        echo "$message" | mail -s "Package Testing: $status" "$NOTIFICATION_EMAIL"
    fi
    
    # Slack notification (if configured)
    if [ -n "$SLACK_WEBHOOK" ]; then
        curl -X POST -H 'Content-type: application/json' \
            --data '{"text":"Package Testing: '"$status"' - '"$message"'"}' \
            "$SLACK_WEBHOOK"
    fi
    
    # Log notification
    echo "$(date): $status - $message" >> "$PIPELINE_DIR/logs/notifications.log"
}

# Run scheduled tests
run_scheduled_tests() {
    local timestamp=$(date +%Y%m%d_%H%M%S)
    local log_file="$PIPELINE_DIR/logs/pipeline-$timestamp.log"
    
    echo "๐Ÿš€ Starting automated testing pipeline at $(date)" | tee "$log_file"
    
    local total_packages=0
    local passed_packages=0
    local failed_packages=0
    
    # Test each configured package
    for package in $PACKAGES_TO_TEST; do
        echo "Testing package: $package" | tee -a "$log_file"
        total_packages=$((total_packages + 1))
        
        local package_passed=true
        
        # Run configured test types
        for test_type in $TEST_TYPES; do
            echo "  Running $test_type test for $package..." | tee -a "$log_file"
            
            case "$test_type" in
                deps)
                    if ! /opt/package-testing/advanced-tests.sh deps "$package" >> "$log_file" 2>&1; then
                        package_passed=false
                    fi
                    ;;
                func)
                    if ! /opt/package-testing/advanced-tests.sh func "$package" "echo 'Basic functionality test'" >> "$log_file" 2>&1; then
                        package_passed=false
                    fi
                    ;;
                security)
                    if ! /opt/package-testing/advanced-tests.sh security "$package" >> "$log_file" 2>&1; then
                        package_passed=false
                    fi
                    ;;
            esac
        done
        
        if [ "$package_passed" = true ]; then
            passed_packages=$((passed_packages + 1))
            echo "  โœ… Package $package: ALL TESTS PASSED" | tee -a "$log_file"
        else
            failed_packages=$((failed_packages + 1))
            echo "  โŒ Package $package: SOME TESTS FAILED" | tee -a "$log_file"
        fi
    done
    
    # Generate summary
    local summary="Pipeline completed: $passed_packages/$total_packages packages passed all tests"
    echo "$summary" | tee -a "$log_file"
    
    # Generate report
    /opt/package-testing/advanced-tests.sh report
    
    # Send notifications
    if [ "$failed_packages" -eq 0 ]; then
        send_notification "$summary" "SUCCESS"
    else
        send_notification "$summary ($failed_packages packages failed)" "WARNING"
    fi
    
    echo "๐Ÿ“Š Pipeline log saved to: $log_file"
}

# Clean up old test data
cleanup_old_tests() {
    echo "๐Ÿงน Cleaning up old test data..."
    
    # Remove logs older than 30 days
    find "$PIPELINE_DIR/logs" -name "*.log" -mtime +30 -delete
    
    # Remove old Docker test images
    docker images | grep "test-" | awk '{print $3}' | xargs -r docker rmi -f
    
    # Clean up temporary files
    find /tmp -name "*test*" -mtime +1 -delete 2>/dev/null || true
    
    echo "โœ… Cleanup completed"
}

# Schedule testing
schedule_tests() {
    echo "๐Ÿ“… Setting up automated testing schedule..."
    
    # Create cron job for daily testing
    cat > /tmp/testing-cron << 'CRON_EOF'
# Automated Package Testing Schedule
0 2 * * * /opt/package-testing/automated-pipeline.sh run
0 3 * * 0 /opt/package-testing/automated-pipeline.sh cleanup
CRON_EOF
    
    crontab /tmp/testing-cron
    rm /tmp/testing-cron
    
    echo "โœ… Automated testing scheduled (daily at 2 AM)"
}

# Main pipeline control
case "$1" in
    run)
        run_scheduled_tests
        ;;
    cleanup)
        cleanup_old_tests
        ;;
    schedule)
        schedule_tests
        ;;
    config)
        echo "๐Ÿ“ Current configuration:"
        cat "$CONFIG_FILE"
        ;;
    *)
        echo "Usage: $0 {run|cleanup|schedule|config}"
        echo "Commands:"
        echo "  run      - Run the testing pipeline"
        echo "  cleanup  - Clean up old test data"
        echo "  schedule - Set up automated scheduling"
        echo "  config   - Show current configuration"
        ;;
esac
EOF

chmod +x /opt/package-testing/automated-pipeline.sh

# Set up the pipeline
/opt/package-testing/automated-pipeline.sh schedule

# Test the pipeline
echo "๐Ÿงช Testing the automated pipeline..."
/opt/package-testing/automated-pipeline.sh run

What this does: Creates a complete automated testing pipeline! ๐ŸŒŸ

๐Ÿ“Š Quick Summary Table

Test TypePurposeAutomation Level
๐Ÿ”ง DependenciesCheck package conflictsโœ… Fully automated
๐Ÿ› ๏ธ FunctionalityVerify package worksโœ… Semi-automated
๐ŸŽฏ SecurityFind security issuesโœ… Automated scanning
๐ŸŒ PerformanceMeasure resource usageโœ… Benchmarking

๐ŸŽฎ Practice Time!

Letโ€™s practice what you learned! Try these testing examples:

What weโ€™re doing: Testing commonly used packages with our framework.

# Test suite for popular packages
cd /opt/package-testing

# Test essential packages
./test-framework.sh suite curl wget git vim nano

# Test with advanced tests
./advanced-tests.sh full curl "curl --version"
./advanced-tests.sh full git "git --version"

# Generate comprehensive report
./advanced-tests.sh report

echo "Popular packages testing completed! โœ…"

What this does: Tests essential Alpine packages thoroughly! ๐ŸŒŸ

Example 2: Custom Package Test Suite ๐ŸŸก

What weโ€™re doing: Creating custom tests for specific package requirements.

# Create custom test configuration
cat > /opt/package-testing/custom-tests.conf << 'EOF'
# Custom Package Testing Configuration
WEB_PACKAGES="nginx apache2 lighttpd"
DB_PACKAGES="mysql postgresql sqlite"
DEV_PACKAGES="gcc make cmake"
PYTHON_PACKAGES="python3 py3-pip py3-setuptools"
EOF

# Create custom test runner
cat > /opt/package-testing/run-custom-tests.sh << 'EOF'
#!/bin/bash

source /opt/package-testing/custom-tests.conf

echo "๐ŸŽฏ Running Custom Package Test Suites"
echo "===================================="

# Test web server packages
echo "๐ŸŒ Testing web server packages..."
for pkg in $WEB_PACKAGES; do
    echo "Testing $pkg..."
    /opt/package-testing/advanced-tests.sh deps "$pkg"
    /opt/package-testing/advanced-tests.sh func "$pkg" "$pkg -v 2>/dev/null || echo 'Version check'"
done

# Test database packages
echo "๐Ÿ’พ Testing database packages..."
for pkg in $DB_PACKAGES; do
    echo "Testing $pkg..."
    /opt/package-testing/advanced-tests.sh deps "$pkg"
done

# Generate custom report
echo "๐Ÿ“Š Generating custom test report..."
/opt/package-testing/advanced-tests.sh report

echo "โœ… Custom testing completed!"
EOF

chmod +x /opt/package-testing/run-custom-tests.sh

# Run custom tests
/opt/package-testing/run-custom-tests.sh

echo "Custom test suite created and executed! ๐Ÿ“š"

What this does: Provides specialized testing for different package categories! ๐Ÿ“š

๐Ÿšจ Fix Common Problems

Problem 1: Docker containers not starting โŒ

What happened: Testing containers fail to start or run. How to fix it: Check Docker service and permissions!

# Fix Docker issues
rc-service docker start
rc-update add docker

# Add user to docker group
adduser $USER docker

# Test Docker functionality
docker run --rm alpine:latest echo "Docker working"

Problem 2: Tests taking too long โŒ

What happened: Package tests run extremely slowly. How to fix it: Optimize test containers and parallel execution!

# Create faster test containers
cat > /opt/package-testing/containers/fast-template.dockerfile << 'EOF'
FROM alpine:latest
RUN apk add --no-cache --virtual .test-deps bash curl
WORKDIR /test
EOF

# Use parallel testing
echo "Running tests in parallel..."
for pkg in curl wget git; do
    /opt/package-testing/test-framework.sh test "$pkg" &
done
wait

Problem 3: Test results not saving โŒ

What happened: Test results are lost or not properly recorded. How to fix it: Check file permissions and disk space!

# Fix permissions
chown -R root:root /opt/package-testing
chmod -R 755 /opt/package-testing

# Check disk space
df -h /opt

# Verify results directory
ls -la /opt/package-testing/results/

Donโ€™t worry! Testing frameworks can be complex to set up. Youโ€™re doing great! ๐Ÿ’ช

๐Ÿ’ก Simple Tips

  1. Start with simple tests ๐Ÿ“… - Build complexity gradually
  2. Use containers for isolation ๐ŸŒฑ - Prevent system contamination
  3. Automate everything possible ๐Ÿค - Reduce manual work
  4. Monitor test performance ๐Ÿ’ช - Keep tests fast and efficient

โœ… Check Everything Works

Letโ€™s verify the testing framework is fully functional:

# Complete framework verification
echo "๐Ÿงช Package Testing Framework Verification"
echo "========================================"

# Test 1: Framework initialization
echo "1. Testing framework initialization..."
/opt/package-testing/test-framework.sh init

# Test 2: Basic package test
echo "2. Testing basic package functionality..."
/opt/package-testing/test-framework.sh test curl

# Test 3: Advanced tests
echo "3. Testing advanced test features..."
/opt/package-testing/advanced-tests.sh deps wget

# Test 4: Report generation
echo "4. Testing report generation..."
/opt/package-testing/advanced-tests.sh report

# Test 5: Automated pipeline
echo "5. Testing automated pipeline..."
/opt/package-testing/automated-pipeline.sh config

# Check all components
echo "6. Verifying all components..."
ls -la /opt/package-testing/

echo "All testing framework verification completed! โœ…"

Good output:

1. Testing framework initialization... โœ…
2. Testing basic package functionality... โœ… 
3. Testing advanced test features... โœ…
4. Testing report generation... ๐Ÿ“Š Report generated
5. Testing automated pipeline... ๐Ÿ“ Configuration loaded
6. Verifying all components... All files present
All testing framework verification completed! โœ…

๐Ÿ† What You Learned

Great job! Now you can:

  • โœ… Set up isolated package testing environments
  • โœ… Create comprehensive test suites for packages
  • โœ… Automate testing workflows with scheduling
  • โœ… Generate detailed testing reports and notifications!

๐ŸŽฏ Whatโ€™s Next?

Now you can try:

  • ๐Ÿ“š Learning about integration testing across multiple packages
  • ๐Ÿ› ๏ธ Setting up performance benchmarking suites
  • ๐Ÿค Implementing continuous integration with Git hooks
  • ๐ŸŒŸ Building package quality gates and approval workflows!

Remember: Every quality assurance engineer was once a beginner. Youโ€™re doing amazing! ๐ŸŽ‰

Keep practicing and youโ€™ll become an expert too! ๐Ÿ’ซ