الجافا الذي فعلاً تستخدمها بالأتمتة

مقال مجاني 7 دقيقة

مقدمة

آخر درس قبل لا تروح تتعلّم جافا — وهو الدرس الذي يجعلك تتعلّمها بهدف.

لأنه في فرق كبير بين إنك تتعلّم جافا "عموماً" وإنك تتعلّمها وانت تعرف وين ستستخدم كل جزء. والثاني أسرع بمراتب، لأنه كل مفهوم بيلتصق بسياق حقيقي.

فهذا الدرس يوريك الكود الذي سنكتبه بباقي الكورس — ويربط كل قطعة جافا بمكانها.

نصيحة
لا تحاول تفهم الكود كامل الآن. مرّ عليه، وشوف الأنماط. وبعد لا تخلّص كورس الجافا، ارجع لهاد الدرس — ستلاقي إنك بتفهمه كله. وهذا بحد ذاته أفضل فحص جهوزية.

الأهداف التعليمية

بنهاية هذا الدرس، ستكون قادراً على:

  • تشوف الجافا الذي ستستخدمها فعلياً
  • تربط كل مفهوم بمكانه بالكورس
  • تعرف نسبة كل مفهوم من كودك
  • تستخدم هذا الدرس كفحص جهوزية

1. الكلاسات والكائنات — 90% من كودك

كل ملف بمشروعك كلاس.

public class LoginPage extends BasePage {

    private static final By EMAIL    = By.cssSelector("[data-test='email']");
    private static final By PASSWORD = By.cssSelector("[data-test='password']");
    private static final By SUBMIT   = By.cssSelector("[data-test='submit']");

    public DashboardPage login(String email, String password) {
        type(EMAIL, email);
        type(PASSWORD, password);
        click(SUBMIT);
        return new DashboardPage();
    }
}

ماذا تحتاج تفهمه هون:

  • public class — تعريف كلاس
  • extends — وراثة
  • private static final — حقل ثابت مخفي
  • دالة إلها معاملات وقيمة رجوع
  • new DashboardPage() — إنشاء كائن

خمسة مفاهيم، وهذا 90% من كودك اليومي.


2. الوراثة والتجريد — الأساس المشترك

public abstract class BasePage {

    protected final WebDriver driver;
    protected final WebDriverWait wait;

    protected BasePage() {
        this.driver = DriverManager.get();
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    protected void click(By locator) {
        wait.until(ExpectedConditions.elementToBeClickable(locator)).click();
    }

    protected void type(By locator, String text) {
        WebElement el = wait.until(ExpectedConditions.elementToBeClickable(locator));
        el.clear();
        el.sendKeys(text);
    }
}

ماذا تحتاج تفهمه:

  • abstract — كلاس لا تستطيع أن تنشئه مباشرة
  • protected — متاح للأبناء بس
  • this — الإشارة للكائن الحالي
  • الـ constructor
مهم
protected مقابل private مقابل public مهم هون تحديداً: - private — الكلاس هذا بس - protected — الكلاس وأبناؤه ← وهذا ما بدنا للـ BasePage - public — الكل لو حطيت private بالـ BasePage، الصفحات لا ترى الدوال. وهذا أشهر خطأ بأول أسبوع بعد جافا.

3. القوائم والـ Maps — كلما يكون في عدة عناصر

// قائمة عناصر
List<WebElement> rows = driver.findElements(By.cssSelector(".item-row"));
int count = rows.size();

// تحويل لقائمة نصوص
List<String> names = new ArrayList<>();
for (WebElement row : rows) {
    names.add(row.getText());
}

// Map للكوكيز
Map<String, String> cookies = new HashMap<>();
cookies.put("session_token", token);

for (Map.Entry<String, String> entry : cookies.entrySet()) {
    driver.manage().addCookie(new Cookie(entry.getKey(), entry.getValue()));
}

ماذا تحتاج: List و ArrayList و Map و HashMap، والحلقة for-each، وsize() وadd() وput().


4. الـ Streams — نسخة أنضف من الحلقة

// نفس اللي فوق بـ Stream
List<String> names = driver.findElements(By.cssSelector(".item-row")).stream()
    .map(WebElement::getText)
    .toList();

// فلترة
List<WebElement> enabled = driver.findElements(By.cssSelector("button")).stream()
    .filter(WebElement::isEnabled)
    .toList();

// عدّ
long completed = todos.stream().filter(Todo::isCompleted).count();
نصيحة
تحتاج map و filter و toList و count. وبس. الـ Streams المتقدمة (flatMap، Collectors.groupingBy) لن تحتاجها إلا نادراً. ولو احتجتها، بتدوّر عليها وقتها. وWebElement::getText (مرجع دالة) تقرأ "خذ النص من كل عنصر" — أنضف من el -> el.getText()، لكن الاثنين نفس الشيء.

5. الاستثناءات — التعامل مع الأخطاء المتوقّعة

// تجاهل متوقّع
protected void dismissAlertIfPresent() {
    try {
        driver.switchTo().alert().accept();
    } catch (NoAlertPresentException ignored) {
      // لا يوجد تنبيه — وهذا الوضع الطبيعي
    }
}

// تنضيف مضمون
protected void withinFrame(By frame, Runnable actions) {
    wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(frame));
    try {
        actions.run();
    } finally {
        driver.switchTo().defaultContent();   // ← يعمل دايماً
    }
}

// رمي استثناء واضح
public static WebDriver get() {
    WebDriver driver = DRIVER.get();
    if (driver == null) {
        throw new IllegalStateException("ما في WebDriver لهاد الخيط");
    }
    return driver;
}

ماذا تحتاج: try/catch، وfinally، وthrow new، والفرق بين الاستثناءات المفحوصة وغير المفحوصة.

مهم
finally هي الأهم هون. لأنها تضمن التنضيف حتى لو صار خطأ — وهذا يمنع "ضلّيت جوا الإطار" و"المتصفح ضلّ مفتوح" اللي ستشوفهم بالكورس.

6. الـ Enums — القيم المحدودة

public enum Browser {

    CHROME(() -> {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--window-size=1920,1080");
        return new ChromeDriver(options);
    }),

    FIREFOX(() -> new FirefoxDriver());

    private final Supplier<WebDriver> supplier;

    Browser(Supplier<WebDriver> supplier) { this.supplier = supplier; }

    public WebDriver create() { return supplier.get(); }
}

ماذا تحتاج: تعريف enum، وإنه يستطيع يحمل حقول ودوال، وvalueOf وvalues().


7. الـ Records — كائنات البيانات

public record UserData(String firstName, String lastName, String email, String password) {

    public static UserData valid() {
        String unique = Thread.currentThread().getId() + "-" + System.currentTimeMillis();
        return new UserData("أحمد", "علي", "user-" + unique + "@test.com", "P@ss123");
    }

    public UserData withEmail(String email) {
        return new UserData(firstName, lastName, email, password);
    }
}

ماذا تحتاج: تعريف record، وإنه بيولّد getters تلقائياً (بدون get)، وإنه غير قابل للتغيير.


8. الـ Lambda والواجهات الوظيفية

// lambda بـ WebDriverWait
wait.until(d -> d.findElements(By.cssSelector(".row")).size() >= 3);

// Supplier
Supplier<WebDriver> chromeSupplier = () -> new ChromeDriver();
WebDriver driver = chromeSupplier.get();

// Runnable
withinFrame(PAYMENT_FRAME, () -> {
    type(CARD_NUMBER, "4242424242424242");
    click(PAY);
});

ماذا تحتاج: صيغة x -> ... و() -> ...، وSupplier وRunnable وFunction الأساسيات.


9. الـ Generics — قراءة بس

List<WebElement>            // قائمة من WebElement
Map<String, String>         // خرائط نص لنص
ThreadLocal<WebDriver>      // ThreadLocal يحمل WebDriver
Supplier<WebDriver>         // مصنع بيرجّع WebDriver
Optional<TodoResponse>      // ممكن يكون فيه قيمة أو لأ
نصيحة
تحتاج تقرا الـ Generics، مش تكتبها. يعني لازم تفهم إنه ThreadLocal<WebDriver> معناها "ThreadLocal يحمل WebDriver". لكن لن تحتاج تكتب كلاس generic بنفسك بمشروع أتمتة عادي. وهذا بيوفّر عليك وقت كثير — لأنه كتابة الـ generics هي الجزء الصعب، والقراءة سهلة.

النسب الحقيقية

المفهوم نسبة كودك
كلاسات وكائنات 40%
دوال ومعاملات 20%
وراثة وتجريد 15%
قوائم وMaps 10%
استثناءات 5%
Enums و Records 5%
Streams و Lambda 5%
مهم
75% من كودك هو كلاسات ودوال ووراثة. فلو أتقنت هالثلاثة، أنت جاهز لباقي الكورس — والباقي تتعلّمه بالسياق وانت تعمل. وهذا بالضبط ليش قلنا "افهم 70% وكمّل" بالدرس السابق.

فحص الجهوزية النهائي

ارجع لأمثلة الكود فوق. إذا تستطيع أن تقرا 6 من 9 منهم وتفهم ماذا يصير — أنت جاهز.

لا تستطيع؟ ارجع للجزء الناقص بكورس الجافا. وهذا أرخص من إنك تكمّل على أساس ناقص.


خلاصة الدرس

  1. تعلّم جافا وانت تعرف وين ستستخدم كل جزء — أسرع بمراتب من تعلّمها "عموماً".

  2. الكلاسات والكائنات 90% من كودك — وكل ملف بمشروعك كلاس.

  3. protected هي المفتاح بـ BasePage — وprivate تجعل الصفحات لا تشوف الدوال.

  4. تحتاج من الـ Streams: map و filter و toList و count. وبس.

  5. finally أهم جزء بالاستثناءات — تمنع "ضلّيت جوا الإطار" و"المتصفح ضلّ مفتوح".

  6. الـ Enums تحمل حقول ودوال — وهذا ما يجعل Driver Factory أنيق.

  7. الـ Records بتولّد getters بدون get — وغير قابلة للتغيير، فآمنة بالتوازي.

  8. تحتاج تقرا الـ Generics مش تكتبها — وهذا بيوفّر وقت كبير.

  9. 75% من كودك: كلاسات ودوال ووراثة. أتقن الثلاثة وأنت جاهز.

  10. الفحص النهائي: اقرا 6 من 9 أمثلة فوق وافهمها.


وبهيك خلصنا قسم الجافا. يلا روح خذ الكورس على القناة، وشوفك بالقسم السادس — Maven و TestNG.

بالنجاح! 💪