অনুশীলনে উপাদান পরীক্ষা

ব্যবহারিক পরীক্ষার কোড প্রদর্শন শুরু করার জন্য উপাদান পরীক্ষা একটি ভাল জায়গা। কম্পোনেন্ট পরীক্ষাগুলি সাধারণ ইউনিট পরীক্ষার চেয়ে বেশি গুরুত্বপূর্ণ, এন্ড-টু-এন্ড পরীক্ষার চেয়ে কম জটিল এবং DOM-এর সাথে ইন্টারঅ্যাকশন প্রদর্শন করে। আরও দার্শনিকভাবে, প্রতিক্রিয়ার ব্যবহার ওয়েব ডেভেলপারদের জন্য ওয়েবসাইট বা ওয়েব অ্যাপগুলিকে উপাদানগুলির সমন্বয়ে গঠিত বলে মনে করা সহজ করে তুলেছে।

তাই পৃথক উপাদানগুলি পরীক্ষা করা, সেগুলি যত জটিলই হোক না কেন, একটি নতুন বা বিদ্যমান অ্যাপ্লিকেশন পরীক্ষা করার বিষয়ে চিন্তা করা শুরু করার একটি ভাল উপায়।

এই পৃষ্ঠাটি জটিল বাহ্যিক নির্ভরতা সহ একটি ছোট উপাদান পরীক্ষা করে। এমন একটি উপাদান পরীক্ষা করা সহজ যা অন্য কোনো কোডের সাথে ইন্টারঅ্যাক্ট করে না, যেমন একটি বোতামে ক্লিক করে এবং একটি সংখ্যা বৃদ্ধি নিশ্চিত করে। বাস্তবে, খুব কম কোডটি এরকম, এবং টেস্টিং কোড যেগুলির মধ্যে মিথস্ক্রিয়া নেই তা সীমিত মূল্যের হতে পারে।

(এটি একটি সম্পূর্ণ টিউটোরিয়াল হিসাবে অভিপ্রেত নয়, এবং একটি পরবর্তী বিভাগ, অটোমেটেড টেস্টিং বাস্তবে, একটি নমুনা কোড সহ একটি বাস্তব সাইট পরীক্ষা করবে যা আপনি একটি টিউটোরিয়াল হিসাবে ব্যবহার করতে পারেন৷ যাইহোক, এই পৃষ্ঠাটি এখনও ব্যবহারিক উপাদানের বেশ কয়েকটি উদাহরণ কভার করবে৷ পরীক্ষামূলক.)

পরীক্ষার অধীনে উপাদান

আমরা একটি প্রতিক্রিয়া উপাদান পরীক্ষা করতে Vitest এবং এর JSDOM পরিবেশ ব্যবহার করব। এটি আমাদের ব্রাউজার অনুকরণ করার সময় কমান্ড লাইনে নোড ব্যবহার করে দ্রুত পরীক্ষা চালাতে দেয়।

প্রতিটি নামের পাশে একটি চয়ন বোতাম সহ নামের একটি তালিকা৷
একটি ছোট প্রতিক্রিয়া উপাদান যা নেটওয়ার্ক থেকে ব্যবহারকারীদের একটি তালিকা দেখায়।

UserList নামের এই React কম্পোনেন্ট নেটওয়ার্ক থেকে ব্যবহারকারীদের একটি তালিকা নিয়ে আসে এবং আপনাকে তাদের মধ্যে একটি নির্বাচন করতে দেয়। ব্যবহারকারীদের তালিকা একটি useEffect ভিতরে fetch ব্যবহার করে প্রাপ্ত করা হয়, এবং নির্বাচন হ্যান্ডলারকে Context দ্বারা পাস করা হয়। এটি তার কোড:

import React, { useEffect, useState, useContext } from 'react';
import { UserContext } from './UserContext.tsx';
import { UserRow } from './UserRow.tsx';

export function UserList({ count = 4 }: { count?: number }) {
  const [users, setUsers] = useState<any[]>([]);
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/users?_limit=' + count)
      .then((response) => response.json())
      .then((json) => setUsers(json));
  }, [count]);

  const c = useContext(UserContext);
  return (
    <div>
      <h2>Users</h2>
      <ul>
        {users.map((u) => (
          <li key={u.id}>
            <button onClick={() => c.userChosen(u.id)}>Choose</button>{' '}
            <UserRow u={u} />
          </li>
        ))}
      </ul>
    </div>
  );
}

এই উদাহরণটি প্রতিক্রিয়ার সর্বোত্তম অনুশীলনগুলি প্রদর্শন করে না (উদাহরণস্বরূপ, এটি ব্যবহার করে fetch ভিতরে useEffect ), তবে আপনার কোডবেসে এটির মতো অনেকগুলি ক্ষেত্রে থাকতে পারে। মোদ্দা কথা, এই কেসগুলি প্রথম নজরে পরীক্ষা করার জন্য একগুঁয়ে দেখাতে পারে। এই কোর্সের একটি ভবিষ্যত বিভাগে পরীক্ষাযোগ্য কোড লেখার বিষয়ে বিস্তারিত আলোচনা করা হবে।

এই উদাহরণে আমরা যে জিনিসগুলি পরীক্ষা করছি তা এখানে::

  • চেক করুন যে নেটওয়ার্ক থেকে ডেটার প্রতিক্রিয়া হিসাবে কিছু সঠিক DOM তৈরি হয়েছে।
  • নিশ্চিত করুন যে একজন ব্যবহারকারী ক্লিক করলে কলব্যাক ট্রিগার হয়।

প্রতিটি উপাদান আলাদা। কি এই এক পরীক্ষা আকর্ষণীয় করে তোলে?

  • নেটওয়ার্ক থেকে রিয়েল-লাইফ ডেটার অনুরোধ করতে এটি গ্লোবাল fetch ব্যবহার করে, যা পরীক্ষার অধীনে ফ্ল্যাকি বা ধীর হতে পারে।
  • এটি অন্য একটি ক্লাস আমদানি করে, UserRow , যা আমরা হয়তো পরোক্ষভাবে পরীক্ষা করতে চাই না।
  • এটি একটি Context ব্যবহার করে যা নির্দিষ্টভাবে পরীক্ষার অধীনে কোডের অংশ নয় এবং সাধারণত একটি অভিভাবক উপাদান দ্বারা সরবরাহ করা হয়।

শুরু করার জন্য একটি দ্রুত পরীক্ষা লিখুন

আমরা দ্রুত এই উপাদান সম্পর্কে খুব মৌলিক কিছু পরীক্ষা করতে পারেন. পরিষ্কার হতে, এই উদাহরণ খুব দরকারী নয়! কিন্তু UserList.test.tsx নামক একটি পিয়ার ফাইলে বয়লারপ্লেট সেট আপ করা সহায়ক (মনে রাখবেন, Vitest-এর মতো টেস্ট রানাররা ডিফল্টভাবে, .test.js বা অনুরূপ, .tsx সহ শেষ হওয়া ফাইলগুলি চালাবে):

import { vi, test, assert, afterAll } from 'vitest';
import { render } from '@testing-library/react';
import { UserList } from './UserList.tsx';
import React, { ContextType } from 'react';

test('render', async () => {
  const c = render(<UserList />);

  const headingNode = await c.findAllByText(/Users);
  assert.isNotNull(headingNode);
});

এই পরীক্ষাটি দাবি করে যে যখন উপাদানটি রেন্ডার হয়, এতে "ব্যবহারকারী" পাঠ্য থাকে। এটি কাজ করে যদিও উপাদানটির নেটওয়ার্কে একটি fetch পাঠানোর একটি পার্শ্ব প্রতিক্রিয়া রয়েছে৷ পরীক্ষার শেষে fetch এখনও চলছে, কোনো সেট এন্ডপয়েন্ট নেই। আমরা নিশ্চিত করতে পারি না যে পরীক্ষা শেষ হলে ব্যবহারকারীর কোনো তথ্য দেখানো হচ্ছে, অন্তত সময়সীমার জন্য অপেক্ষা না করে।

মক fetch()

মকিং হল পরীক্ষার জন্য আপনার নিয়ন্ত্রণে থাকা একটি বাস্তব ফাংশন বা ক্লাস প্রতিস্থাপন করার কাজ। সাধারণ ইউনিট পরীক্ষা ব্যতীত প্রায় সব ধরনের পরীক্ষায় এটি সাধারণ অভ্যাস। দাবী এবং অন্যান্য আদিমতে এটি আরও কভার করা হবে।

আপনি আপনার পরীক্ষার জন্য মক fetch() করতে পারেন যাতে এটি দ্রুত সম্পন্ন হয় এবং আপনার প্রত্যাশিত ডেটা ফেরত দেয়, এবং "বাস্তব-বিশ্ব" বা অজানা ডেটা নয়। fetch হল একটি বিশ্বব্যাপী , যার মানে আমাদের এটিকে আমাদের কোডে import বা require নেই।

ভিটেস্টে, আপনি vi.fn() দ্বারা ফেরত দেওয়া একটি বিশেষ বস্তুর সাহায্যে vi.stubGlobal কল করে একটি বিশ্বব্যাপী উপহাস করতে পারেন —এটি একটি উপহাস তৈরি করে যা আমরা পরে পরিবর্তন করতে পারি। এই পদ্ধতিগুলি এই কোর্সের পরবর্তী বিভাগে আরও বিশদে পরীক্ষা করা হবে, তবে আপনি নিম্নলিখিত কোডে অনুশীলনে সেগুলি দেখতে পাবেন:

test('render', async () => {
  const fetchMock = vi.fn();
  fetchMock.mockReturnValue(
    Promise.resolve({
      json: () => Promise.resolve([{ name: 'Sam', id: 'sam' }]),
    }),
  );
  vi.stubGlobal('fetch', fetchMock);

  const c = render(<UserList />);

  const headingNode = await c.queryByText(/Users);
  assert.isNotNull(headingNode);

  await waitFor(async () => {
    const samNode = await c.queryByText(/Sam);
    assert.isNotNull(samNode);
  });
});

afterAll(() => {
  vi.unstubAllGlobals();
});

এই কোডটি একটি উপহাস যোগ করে, নেটওয়ার্ক ফেচ Response একটি "জাল" সংস্করণ বর্ণনা করে এবং তারপর এটি প্রদর্শিত হওয়ার জন্য অপেক্ষা করে৷ যদি পাঠ্যটি উপস্থিত না হয়- আপনি queryByText এ ক্যোয়ারীটিকে একটি নতুন নামে পরিবর্তন করে এটি পরীক্ষা করতে পারেন- পরীক্ষাটি ব্যর্থ হবে৷

এই উদাহরণটি ভিটেস্টের বিল্ট-ইন মকিং হেল্পার ব্যবহার করেছে, কিন্তু অন্যান্য টেস্টিং ফ্রেমওয়ার্কের উপহাসের ক্ষেত্রে একই পদ্ধতি রয়েছে। Vitest অনন্য যে আপনাকে অবশ্যই সমস্ত পরীক্ষার পরে vi.unstubAllGlobals() কল করতে হবে, অথবা একটি সমতুল্য বৈশ্বিক বিকল্প সেট করতে হবে। আমাদের কাজ "পূর্বাবস্থায়" না করে, fetch মক অন্যান্য পরীক্ষাগুলিকে প্রভাবিত করতে পারে, এবং প্রতিটি অনুরোধের জবাব দেওয়া হবে আমাদের অদ্ভুত স্তূপ JSON দিয়ে!

মক আমদানি

আপনি হয়তো লক্ষ্য করেছেন যে আমাদের UserList উপাদান নিজেই UserRow নামক একটি উপাদান আমদানি করে। যদিও আমরা এর কোডটি অন্তর্ভুক্ত করিনি, আপনি দেখতে পাচ্ছেন যে এটি ব্যবহারকারীর নাম রেন্ডার করে: পূর্ববর্তী পরীক্ষা "স্যাম" এর জন্য পরীক্ষা করে এবং এটি সরাসরি UserList মধ্যে রেন্ডার করা হয় না, তাই এটি অবশ্যই UserRow থেকে আসতে হবে।

ব্যবহারকারীদের নাম কীভাবে আমাদের উপাদানের মধ্য দিয়ে চলে তার একটি ফ্লোচার্ট।
UserListTest এর UserRow এর দৃশ্যমানতা নেই।

যাইহোক, UserRow নিজেই একটি জটিল উপাদান হতে পারে—এটি আরও ব্যবহারকারীর ডেটা আনতে পারে, অথবা এর পার্শ্বপ্রতিক্রিয়া থাকতে পারে যা আমাদের পরীক্ষার সাথে প্রাসঙ্গিক নয়। এই পরিবর্তনশীলতা অপসারণ করা আপনার পরীক্ষাগুলিকে আরও সহায়ক করে তুলবে, বিশেষ করে আপনি যে উপাদানগুলি পরীক্ষা করতে চান সেগুলি আরও জটিল এবং তাদের নির্ভরতার সাথে আরও জড়িত।

সৌভাগ্যবশত, আপনি কিছু আমদানিকে উপহাস করতে Vitest ব্যবহার করতে পারেন, এমনকি আপনার পরীক্ষা সরাসরি সেগুলি ব্যবহার না করলেও, যাতে যেকোন কোড যেগুলি ব্যবহার করে তা একটি সাধারণ বা পরিচিত সংস্করণের সাথে প্রদান করা হয়:

vi.mock('./UserRow.tsx', () => {
  return {
    UserRow(arg) {
      return <>{arg.u.name}</>;
    },
  }
});

test('render', async () => {
  // ...
});

fetch গ্লোবাল নিয়ে উপহাস করার মতো, এটি একটি শক্তিশালী টুল, কিন্তু আপনার কোডে প্রচুর নির্ভরতা থাকলে এটি টেকসই হতে পারে। আবার, এর জন্য সর্বোত্তম সমাধান হল পরীক্ষাযোগ্য কোড লেখা।

ক্লিক করুন এবং প্রসঙ্গ প্রদান করুন

প্রতিক্রিয়া, এবং অন্যান্য লাইব্রেরি যেমন Lit-এ Context নামে একটি ধারণা রয়েছে। নমুনা কোডে একটি UserContext অন্তর্ভুক্ত থাকে যা কোনো ব্যবহারকারীকে বেছে নেওয়া হলে পদ্ধতির আমন্ত্রণ জানায়। এটি প্রায়শই "প্রপ ড্রিলিং" এর বিকল্প হিসাবে দেখা হয়, যেখানে কলব্যাক সরাসরি UserList পাঠানো হয়।

আমরা যে পরীক্ষার জোতা লিখেছি তা UserContext প্রদান করেনি। এটি ছাড়া প্রতিক্রিয়া পরীক্ষায় একটি ক্লিক অ্যাকশন যোগ করার মাধ্যমে, এটি, সবচেয়ে খারাপভাবে, পরীক্ষাটি ক্র্যাশ করবে, বা সর্বোত্তমভাবে, যদি অন্য কোথাও একটি ডিফল্ট উদাহরণ প্রদান করা হয়, তবে কিছু আচরণ আমাদের নিয়ন্ত্রণের বাইরে ঘটাবে (উপরের একটি অজানা UserRow মতো):

  const c = render(<UserList />);
  const chooseButton = await c.getByText(/Choose);
  chooseButton.click();

পরিবর্তে, উপাদান রেন্ডার করার সময়, আপনি আপনার নিজস্ব Context প্রদান করতে পারেন। এই উদাহরণটি vi.fn() এর একটি উদাহরণ ব্যবহার করে, একটি Vitest মক ফাংশন, যা একটি কল করা হয়েছে কিনা এবং এটি কোন যুক্তি দিয়ে করা হয়েছিল তা যাচাই করার জন্য ব্যবহার করা যেতে পারে। আমাদের ক্ষেত্রে, এটি পূর্বের উদাহরণে উপহাসিত fetch সাথে ইন্টারঅ্যাক্ট করে, এবং পরীক্ষাটি নিশ্চিত করতে পারে যে আইডিটি "স্যাম" ছিল:

  const userChosenFn = vi.fn();
  const ucForTest: ContextType<typeof UserContext> = { userChosen: userChosenFn as any };
  const c = render(
    <UserContext.Provider value={ucForTest}>
      <UserList />
    </UserContext.Provider>,
  );

  const chooseButton = await c.getByText(/Choose);
  chooseButton.click();
  assert.deepStrictEqual(userChosenFn.mock.calls, [['sam']]);

এটি একটি সাধারণ কিন্তু শক্তিশালী প্যাটার্ন যা আপনাকে মূল উপাদান থেকে অপ্রাসঙ্গিক নির্ভরতা অপসারণ করতে দেয় যা আপনি পরীক্ষা করার চেষ্টা করছেন।

সংক্ষেপে

এটি একটি দ্রুত এবং সরলীকৃত উদাহরণ যা একটি কঠিন--পরীক্ষা প্রতিক্রিয়া উপাদান পরীক্ষা এবং সুরক্ষিত করার জন্য কীভাবে একটি উপাদান পরীক্ষা তৈরি করতে হয় তা প্রদর্শন করে, উপাদানটি তার নির্ভরতার সাথে সঠিকভাবে ইন্টারঅ্যাক্ট করে তা নিশ্চিত করার উপর ফোকাস করে (গ্লোবাল fetch , একটি আমদানি করা সাবকম্পোনেন্ট, এবং একটি Context )।

আপনার উপলব্ধি পরীক্ষা করুন

প্রতিক্রিয়া উপাদান পরীক্ষা করার জন্য কোন পদ্ধতি ব্যবহার করা হয়েছিল?

পরীক্ষার জন্য সহজ বেশী সঙ্গে জটিল নির্ভরতা উপহাস
প্রসঙ্গ ব্যবহার করে নির্ভরতা ইনজেকশন
বিশ্বব্যাপী stubbing
যে একটি সংখ্যা বৃদ্ধি চেক