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

ব্যবহারিক পরীক্ষার কোড প্রদর্শন শুরু করার জন্য উপাদান পরীক্ষা একটি ভাল জায়গা। কম্পোনেন্ট পরীক্ষাগুলি সাধারণ ইউনিট পরীক্ষার চেয়ে বেশি গুরুত্বপূর্ণ, এন্ড-টু-এন্ড পরীক্ষার চেয়ে কম জটিল এবং 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 সাথে ইন্টারঅ্যাক্ট করে এবং পরীক্ষাটি নিশ্চিত করতে পারে যে আইডিটি sam ছিল:

  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
যে একটি সংখ্যা বৃদ্ধি চেক