পিএইচপিউনিট দিয়ে সুরক্ষিত পদ্ধতিগুলি পরীক্ষা করার সেরা অনুশীলন


287

আমি কী আপনি ব্যক্তিগত পদ্ধতিটি তথ্যমূলক পরীক্ষার বিষয়ে আলোচনাটি পেয়েছি ।

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

আমি নিম্নলিখিত সম্পর্কে চিন্তা:

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

কোনটি সেরা অনুশীলন? আর কিছু আছে?

দেখে মনে হচ্ছে, JUnit সুরক্ষিত পদ্ধতিগুলি সর্বজনীন হওয়ার জন্য স্বয়ংক্রিয়ভাবে পরিবর্তন করে, তবে আমার এটির আরও গভীর দৃষ্টি নেই। পিএইচপি এই প্রতিচ্ছবি মাধ্যমে অনুমতি দেয় না ।


দুটি প্রশ্ন: 1. আপনার ক্লাসটি প্রকাশিত হয় না কেন পরীক্ষার কার্যকারিতাটি আপনার বিরক্ত করা উচিত? ২. যদি এটি পরীক্ষা করা উচিত তবে এটি ব্যক্তিগত কেন?
nad2000

2
সম্ভবত তিনি পরীক্ষা করতে চান যদি কোনও ব্যক্তিগত সম্পত্তি সঠিকভাবে সেট করা হচ্ছে এবং কেবল সেটার ফাংশনটি ব্যবহার করে পরীক্ষার একমাত্র উপায় হল ব্যক্তিগত সম্পত্তিটি জনসাধারণের কাছে করা এবং ডেটা পরীক্ষা করা
আন্তোনিওসিএস

4
এবং তাই এটি আলোচনা-স্টাইল এবং এইভাবে গঠনমূলক নয়। আবার :)
mlvljr

72
আপনি এটিকে সাইটের নিয়মের বিপরীতে কল করতে পারেন, তবে কেবল এটি "গঠনমূলক নয়" বলা এটি আপত্তিজনক।
অ্যান্ডি ভি

1
@ ভিজার, এটি নিজেকে অপমান করছে;)
পেসারিয়ার

উত্তর:


417

আপনি যদি পিএইচপিউনিট দিয়ে পিএইচপি 5 (> = 5.3.2) ব্যবহার করেন তবে আপনি আপনার ব্যক্তিগত ও সুরক্ষিত পদ্ধতিগুলি পরীক্ষা করে চালানোর আগে সেগুলি সর্বজনীন হতে সেট করার জন্য প্রতিচ্ছবি ব্যবহার করে পরীক্ষা করতে পারেন:

protected static function getMethod($name) {
  $class = new ReflectionClass('MyClass');
  $method = $class->getMethod($name);
  $method->setAccessible(true);
  return $method;
}

public function testFoo() {
  $foo = self::getMethod('foo');
  $obj = new MyClass();
  $foo->invokeArgs($obj, array(...));
  ...
}

27
সেবাস্তিয়ান ব্লগের লিঙ্কটি উদ্ধৃত করার জন্য: "সুতরাং: সুরক্ষিত এবং ব্যক্তিগত বৈশিষ্ট্য এবং পদ্ধতিগুলির পরীক্ষা কেবল সম্ভব হওয়ার অর্থ এই নয় যে এটি একটি" ভাল জিনিস "" - কেবল এটি মাথায় রাখতে
এডোরিয়ান

10
আমি যে প্রতিযোগিতা হবে। যদি কাজ করার জন্য আপনার সুরক্ষিত বা ব্যক্তিগত পদ্ধতিগুলির প্রয়োজন না হয় তবে সেগুলি পরীক্ষা করবেন না।
uckelman

10
কেবল পরিষ্কার করার জন্য, এটি কাজ করার জন্য আপনাকে পিএইচপিউইনাইট ব্যবহার করার দরকার নেই। এটি সিম্পল টেস্ট বা যা কিছু নিয়ে কাজ করবে work উত্তরটি পিএইচপিউনিটের উপর নির্ভরশীল এমন কিছুই নেই।
আয়ান ডান

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

24
@ জিফিলিপ আমার কাছে, protectedপদ্ধতিটি জনসাধারণের এপিআইয়ের একটি অঙ্গ কারণ কোনও তৃতীয় পক্ষের শ্রেণি এটি বাড়িয়ে দিতে পারে এবং কোনও যাদু ছাড়াই এটি ব্যবহার করতে পারে । সুতরাং আমি মনে করি যে কেবল privateপদ্ধতিগুলি সরাসরি পরীক্ষা না করা পদ্ধতিগুলির বিভাগে আসে। protectedএবং publicসরাসরি পরীক্ষা করা উচিত।
ফিলিপ হালাক্সা

48

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

class Foo {
  protected function stuff() {
    // secret stuff, you want to test
  }
}

class SubFoo extends Foo {
  public function exposedStuff() {
    return $this->stuff();
  }
}

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


2
আপনি কেবল সরকারী হিসাবে স্টাফ () সরাসরি প্রয়োগ করতে পারেন এবং প্যারেন্ট :: স্টাফ () ফিরিয়ে দিতে পারেন। আমার প্রতিক্রিয়া দেখুন। মনে হচ্ছে আমি আজ খুব দ্রুত জিনিস পড়ছি।
মাইকেল জনসন

তুমি ঠিক বলছো; সুরক্ষিত পদ্ধতিটিকে জনসাধারণের মধ্যে পরিবর্তন করা বৈধ।
ট্রয়সল্কন

সুতরাং কোডটি আমার তৃতীয় বিকল্পটির পরামর্শ দেয় এবং "নোট করুন যে আপনি সর্বদা রচনা দিয়ে উত্তরাধিকার প্রতিস্থাপন করতে পারেন।" আমার প্রথম বিকল্পের দিকে বা রিফ্যাক্টরিং
ক্যাটাগল

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

36
সুরক্ষিত পদ্ধতি হয় একটি বর্গ ইন্টারফেস অংশ, তারা কেবল বাস্তবায়ন বিবরণ নয়। সুরক্ষিত সদস্যদের পুরো পয়েন্টটি যাতে সাবক্ল্যাসাররা (তাদের নিজস্ব ডানায় ব্যবহারকারীরা) শ্রেণিবদ্ধের ভিতরে সেই সুরক্ষিত পদ্ধতিগুলি ব্যবহার করতে পারে। সেগুলি পরিষ্কারভাবে পরীক্ষা করা দরকার।
বিটি

40

টিস্টবার্নের সঠিক পন্থা রয়েছে। এমনকি সহজ পদ্ধতিটি সরাসরি কল করা এবং উত্তরটি ফেরত দেওয়া:

class PHPUnitUtil
{
  public static function callMethod($obj, $name, array $args) {
        $class = new \ReflectionClass($obj);
        $method = $class->getMethod($name);
        $method->setAccessible(true);
        return $method->invokeArgs($obj, $args);
    }
}

আপনি নিজের পরীক্ষায় এটিকে কল করে বলতে পারেন:

$returnVal = PHPUnitUtil::callMethod(
                $this->object,
                '_nameOfProtectedMethod', 
                array($arg1, $arg2)
             );

1
ধন্যবাদ এটি একটি দুর্দান্ত উদাহরণ। সুরক্ষার পরিবর্তে পদ্ধতিটি সর্বজনীন হওয়া উচিত, তাই না?
ভাল

ভাল যুক্তি. আমি আসলে আমার বেস ক্লাসে এই পদ্ধতিটি ব্যবহার করি যা থেকে আমার পরীক্ষার ক্লাসগুলি প্রসারিত হয়, এক্ষেত্রে এটি বোঝা যায়। শ্রেণীর নাম যদিও এখানে ভুল হবে।
Robert.egginton

আমি টেস্টবার্ন এক্সডি এর ভিত্তিতে কোডের ঠিক একই টুকরোটি তৈরি করেছি
নেবুলোসার

23

আমি উক্কেলম্যানের উত্তরে সংজ্ঞায়িত করা মেঠোথ () এ সামান্য পরিবর্তনের প্রস্তাব দিতে চাই

এই কোডটি হার্ড-কোডড মানগুলি মুছে ফেলে এবং ব্যবহারকে কিছুটা সরল করে getMethod () পরিবর্তন করে। আমি নীচের উদাহরণ হিসাবে বা আপনার পিএইচপিউনিট_ফ্রেমওয়ার্ক_স্টেস কেস-প্রসারিত শ্রেণিতে (বা, আমি মনে করি, বিশ্বব্যাপী আপনার পিএইচপিউইনটিল ফাইলটিতে) এটি আপনার পিএইচপিউইনটিল শ্রেণিতে যুক্ত করার পরামর্শ দিচ্ছি।

যেহেতু মাইক্লাস যেভাবেই ইনস্ট্যান্ট করা হচ্ছে এবং রিফ্লেকশন ক্লাস একটি স্ট্রিং বা কোনও অবজেক্ট নিতে পারে ...

class PHPUnitUtil {
    /**
     * Get a private or protected method for testing/documentation purposes.
     * How to use for MyClass->foo():
     *      $cls = new MyClass();
     *      $foo = PHPUnitUtil::getPrivateMethod($cls, 'foo');
     *      $foo->invoke($cls, $...);
     * @param object $obj The instantiated instance of your class
     * @param string $name The name of your private/protected method
     * @return ReflectionMethod The method you asked for
     */
    public static function getPrivateMethod($obj, $name) {
      $class = new ReflectionClass($obj);
      $method = $class->getMethod($name);
      $method->setAccessible(true);
      return $method;
    }
    // ... some other functions
}

যা প্রত্যাশা করা হয় তা স্পষ্ট হওয়ার জন্য আমি একটি উপনাম ফাংশন getProtectedMethod () তৈরি করেছি, তবে এটি আপনার হাতে।

চিয়ার্স!


প্রতিচ্ছবি শ্রেণীর এপিআই ব্যবহারের জন্য +1।
বিল অর্টেল

10

আমার মনে হয় ট্রলসকেন খুব কাছে। আমি পরিবর্তে এটি করতে হবে:

class ClassToTest
{
   protected function testThisMethod()
   {
     // Implement stuff here
   }
}

তারপরে, এরকম কিছু বাস্তবায়ন করুন:

class TestClassToTest extends ClassToTest
{
  public function testThisMethod()
  {
    return parent::testThisMethod();
  }
}

এরপরে আপনি টেস্টক্লাসটোস্টেস্টের বিরুদ্ধে আপনার পরীক্ষা চালান।

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


হি ... মনে হচ্ছে আমি বলছি, আপনার তৃতীয় বিকল্পটি ব্যবহার করুন :)
মাইকেল জনসন

2
হ্যাঁ, এটি আমার তৃতীয় বিকল্প। আমি বেশ নিশ্চিত, যে পিএইচপিউইনিট এই জাতীয় ব্যবস্থা দেয় না।
GRGr

এটি কাজ করবে না, আপনি একই নামে কোনও পাবলিক ফাংশন সহ সুরক্ষিত ফাংশনটিকে ওভাররাইড করতে পারবেন না।
কোয়েন

আমি ভুল হতে পারি, তবে আমি মনে করি না এই পদ্ধতির কাজ হতে পারে। পিএইচপিউনিট (যতদূর আমি এটি ব্যবহার করেছি) আপনার পরীক্ষার শ্রেণীর জন্য এমন আরও একটি ক্লাস বাড়ানো দরকার যা প্রকৃত পরীক্ষার কার্যকারিতা সরবরাহ করে। আশেপাশের কোনও উপায় না থাকলে আমি নিশ্চিত না যে এই উত্তরটি কীভাবে ব্যবহার করা যেতে পারে তা আমি দেখতে পাচ্ছি। phpunit.de/manual/current/en/…
সাইফার

এফওয়াইআই এই অনলাইনটি সুরক্ষিত পদ্ধতির জন্য কাজ করে, ব্যক্তিগতগুলির জন্য নয়
সিকিক

5

আমি আমার টুপিটি এখানে রিংয়ের মধ্যে ফেলে দিতে যাচ্ছি:

আমি সাফল্যের মিশ্র ডিগ্রি সহ __call হ্যাক ব্যবহার করেছি। আমি যে বিকল্পটি নিয়ে এসেছি তা হ'ল ভিজিটর প্যাটার্নটি ব্যবহার করা:

1: একটি স্টাডি ক্লাস বা কাস্টম ক্লাস তৈরি করুন (প্রকার প্রয়োগের জন্য)

2: প্রাইম যে প্রয়োজনীয় পদ্ধতি এবং তর্ক সঙ্গে

3: নিশ্চিত করুন যে আপনার এসইটির একটি গ্রহণযোগ্যভিসিটার পদ্ধতি রয়েছে যা পরিদর্শন ক্লাসে বর্ণিত যুক্তির সাহায্যে পদ্ধতিটি কার্যকর করবে will

4: আপনি যে শ্রেণিতে পরীক্ষা করতে চান তাতে এটি প্রবেশ করুন

5: SUT দর্শনার্থীর মধ্যে অপারেশন ফলাফল ইনজেকশন

6: ভিজিটরের ফলাফলের বৈশিষ্ট্যে আপনার পরীক্ষার শর্তগুলি প্রয়োগ করুন


1
একটি আকর্ষণীয় সমাধান জন্য +1
jsh

5

সুরক্ষিত পদ্ধতিতে অ্যাক্সেস করতে আপনি জেনেরিক ফ্যাশনে প্রকৃতপক্ষে __call () ব্যবহার করতে পারেন। এই ক্লাস পরীক্ষা করতে সক্ষম হতে

class Example {
    protected function getMessage() {
        return 'hello';
    }
}

আপনি উদাহরণ টেষ্ট.এফপিতে একটি সাবক্লাস তৈরি করেছেন:

class ExampleExposed extends Example {
    public function __call($method, array $args = array()) {
        if (!method_exists($this, $method))
            throw new BadMethodCallException("method '$method' does not exist");
        return call_user_func_array(array($this, $method), $args);
    }
}

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

এখন পরীক্ষার কেসটি কেবল তার মধ্যেই পৃথক হয় যেখানে আপনি পরীক্ষার জন্য অবজেক্টটি তৈরি করেন, উদাহরণস্বরূপ উদাহরণের জন্য অদলবদল করে।

class ExampleTest extends PHPUnit_Framework_TestCase {
    function testGetMessage() {
        $fixture = new ExampleExposed();
        self::assertEquals('hello', $fixture->getMessage());
    }
}

আমি বিশ্বাস করি পিএইচপি 5.3 আপনাকে সরাসরি পদ্ধতির অ্যাক্সেসিবিলিটি পরিবর্তন করার জন্য প্রতিবিম্ব ব্যবহার করার অনুমতি দেয়, তবে আমি ধরে নিই যে পৃথকভাবে প্রতিটি পদ্ধতির জন্য আপনাকে এটি করতে হবে।


1
__Call () বাস্তবায়ন দুর্দান্ত কাজ করে! আমি ভোট দেওয়ার চেষ্টা করেছি, তবে আমি এই পদ্ধতিটি পরীক্ষা না করা পর্যন্ত আমার ভোটটি আনসেট করেছি এবং এসওতে সময়সীমা থাকার কারণে এখন আমাকে ভোট দেওয়ার অনুমতি দেওয়া হচ্ছে না।
অ্যাডাম ফ্রাঙ্কো

call_user_method_array()ফাংশন পিএইচপি 4.1.0 এ অনুমোদিত নয় ... ব্যবহার call_user_func_array(array($this, $method), $args)পরিবর্তে। মনে রাখবেন যে আপনি যদি পিএইচপি 5.3.2+ ব্যবহার করেন তবে আপনি সুরক্ষিত / ব্যক্তিগত পদ্ধতি এবং বৈশিষ্ট্যগুলিতে অ্যাক্সেস পেতে
nuqqsa

@ নাক্কসা - ধন্যবাদ, আমি আমার উত্তর আপডেট করেছি। আমি তখন থেকে একটি জেনেরিক Accessibleপ্যাকেজ লিখেছি যা পরীক্ষাগুলিকে ব্যক্তিগত / সুরক্ষিত বৈশিষ্ট্য এবং শ্রেণি এবং অবজেক্টের পদ্ধতিতে অ্যাক্সেসের অনুমতি দেওয়ার জন্য প্রতিফলন ব্যবহার করে।
ডেভিড হার্কনেস

এই কোডটি পিএইচপি 5.2.7 এ আমার জন্য কাজ করে না - বেস শ্রেণিটি যে পদ্ধতিগুলি সংজ্ঞায়িত করে তার জন্য __call পদ্ধতিটি অনুরোধ করে না। আমি এটি নথিভুক্ত খুঁজে পাচ্ছি না, তবে আমি অনুমান করছি যে এই আচরণটি পিএইচপি 5.3-এ পরিবর্তিত হয়েছিল (যেখানে আমি নিশ্চিত করেছি যে এটি কাজ করে))
রাসেল ডেভিস

@ রাসেল - __call()কেবলমাত্র যদি আহ্বানকারী পদ্ধতিতে অ্যাক্সেস না করে তবেই অনুরোধ করা হবে। যেহেতু ক্লাস এবং এর সাবক্লাসগুলি সুরক্ষিত পদ্ধতিতে অ্যাক্সেস পেয়েছে তাই তাদের কলগুলি অতিক্রম করবে না __call()। আপনি কি আপনার কোড পোস্ট করতে পারেন যা একটি নতুন প্রশ্নে 5.2.7 এ কাজ করে না? আমি উপরেরটি 5.2 তে ব্যবহার করেছি এবং কেবল 5.3.2 দিয়ে প্রতিবিম্বটি ব্যবহার করতে চলেছি।
ডেভিড হার্কনেস

2

আমি "হেনরিক পল" এর কার্যকরী / ধারণাটির জন্য নীচে কাজ করার পরামর্শ দিচ্ছি :)

আপনি আপনার শ্রেণীর ব্যক্তিগত পদ্ধতির নামগুলি জানেন। উদাহরণস্বরূপ এগুলি _ অ্যাড (), _এডিট (), _ ডিলিট () ইত্যাদি are

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

চেষ্টা কর.

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.