কেন অবশ্যই ইউনাইটের ফিক্সচারসেটআপ স্থির থাকতে হবে?


109

আমি jUnit এর @ বিফোরক্লাস টীকা সহ একটি পদ্ধতি চিহ্নিত করেছি এবং এটি অবশ্যই স্থির থাকতে হবে বলে এই ব্যতিক্রম পেয়েছে। যুক্তি কী? এটি যতদূর আমি দেখছি কোনও সঙ্গত কারণেই এটি আমার সমস্ত সূত্রকে স্থির ক্ষেত্রগুলিতে থাকতে বাধ্য করে।

নেট। (NUnit) এ, এটি ক্ষেত্রে নয়।

সম্পাদনা করুন - @ বিফোরক্লাসের দ্বারা বর্ণিত একটি পদ্ধতি কেবল একবার স্থিতিশীল পদ্ধতি হওয়ার সাথে কিছুই করার নেই - এটির জন্য একটি স্থির-অবিচল পদ্ধতি কেবল একবার চালানো যেতে পারে (নুনিট হিসাবে)।

উত্তর:


122

JUnit সর্বদা প্রতিটি @ টেস্ট পদ্ধতির জন্য পরীক্ষার শ্রেণীর একটি উদাহরণ তৈরি করে। পার্শ্ব প্রতিক্রিয়া ছাড়াই পরীক্ষাগুলি লিখতে আরও সহজ করার জন্য এটি একটি মৌলিক নকশার সিদ্ধান্ত । ভাল পরীক্ষাগুলির কোনও অর্ড-অফ-রান নির্ভরতা ( এফআইআরএসটি দেখুন ) নেই এবং পরীক্ষা ক্লাসের তাজা উদাহরণ তৈরি করা এবং প্রতিটি পরীক্ষার জন্য এর উদাহরণ ভেরিয়েবলগুলি এটি অর্জনে গুরুত্বপূর্ণ। কিছু টেস্টিং ফ্রেমওয়ার্কগুলি সমস্ত পরীক্ষার জন্য একই পরীক্ষার শ্রেণীর উদাহরণ পুনরায় ব্যবহার করে, যা পরীক্ষার মধ্যে দুর্ঘটনাক্রমে পার্শ্ব-প্রতিক্রিয়া তৈরির আরও বেশি সম্ভাবনা নিয়ে যায়।

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

সুতরাং সেই পদ্ধতিগুলি স্থিতিশীল করার জন্য প্রয়োগ করা একমাত্র যুক্তিযুক্ত সমাধান।

এখানে একটি উদাহরণ:

public class ExampleTest {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("beforeClass");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("afterClass");
    }

    @Before
    public void before() {
        System.out.println(this + "\tbefore");
    }

    @After
    public void after() {
        System.out.println(this + "\tafter");
    }

    @Test
    public void test1() {
        System.out.println(this + "\ttest1");
    }

    @Test
    public void test2() {
        System.out.println(this + "\ttest2");
    }

    @Test
    public void test3() {
        System.out.println(this + "\ttest3");
    }
}

কোন মুদ্রণ:

beforeClass
ExampleTest@3358fd70    before
ExampleTest@3358fd70    test1
ExampleTest@3358fd70    after
ExampleTest@6293068a    before
ExampleTest@6293068a    test2
ExampleTest@6293068a    after
ExampleTest@22928095    before
ExampleTest@22928095    test3
ExampleTest@22928095    after
afterClass

আপনি দেখতে পাচ্ছেন, প্রতিটি পরীক্ষার নিজস্ব উদাহরণ দিয়ে সম্পাদন করা হয়। জুনিত যা করে তা মূলত এর মত:

ExampleTest.beforeClass();

ExampleTest t1 = new ExampleTest();
t1.before();
t1.test1();
t1.after();

ExampleTest t2 = new ExampleTest();
t2.before();
t2.test2();
t2.after();

ExampleTest t3 = new ExampleTest();
t3.before();
t3.test3();
t3.after();

ExampleTest.afterClass();

1
"নইলে কোন পরীক্ষার শ্রেণীর উদাহরণের জন্য পদ্ধতিগুলি বলা উচিত?" - পরীক্ষার উদাহরণস্বরূপ যে পরীক্ষাগুলি কার্যকর করতে JUnit পরীক্ষা চলমান তৈরি হয়েছিল।
এইচডিভি

1
এই উদাহরণে এটি তিনটি পরীক্ষার উদাহরণ তৈরি করেছে। সেখানে নেই পরীক্ষা উদাহরণস্বরূপ।
এস্কো লুনটলা

হ্যাঁ - আমি আপনার উদাহরণে এটি মিস করেছি। আমি আরও ভাবছিলাম যে কখন জুনাটকে আলা গ্রহন বা চলন্ত টেস্ট বা মাভেনের একটি পরীক্ষা চালানো হবে thinking এই ক্ষেত্রে পরীক্ষার শ্রেণীর তৈরির একটি উদাহরণ রয়েছে।
এইচডিভি

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

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

43

সংক্ষিপ্ত উত্তরটি হ'ল এটি স্থির হওয়ার কোনও ভাল কারণ নেই।

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


4
আমি আমার নিজের পরীক্ষার কেস সুপারক্লাস লিখেছিলাম এবং @PostConstructসেট আপ করার @AfterClassজন্য এবং ছিঁড়ে ফেলার জন্য স্প্রিং টীকাগুলি ব্যবহার করি এবং আমি জুনিট থেকে স্থির এটিকে সম্পূর্ণ উপেক্ষা করি। ডিএও পরীক্ষার জন্য আমি তখন নিজের TestCaseDataLoaderক্লাসটি লিখেছিলাম যা আমি এই পদ্ধতিগুলি থেকে প্রার্থনা করি।
এইচডিভি

9
এটি একটি ভয়াবহ উত্তর, স্পষ্টত গ্রহণযোগ্য উত্তর স্পষ্টভাবে ইঙ্গিত করার কারণে এটি স্থিতিশীল হওয়ার কারণ আছে। আপনি নকশার সিদ্ধান্তের সাথে একমত হতে পারেন, তবে সিদ্ধান্তের "কোনও ভাল কারণ নেই" তা বোঝানো তো দূরের কথা।
অ্যাডাম পার্কিন

8
অবশ্যই জুনিত লেখকের একটি কারণ ছিল, আমি বলছি এটি একটি ভাল কারণ নয় ... এভাবে ওপি (এবং অন্যান্য 44 জন) এর উত্স রহস্যজনক being উদাহরণস্বরূপ পদ্ধতিগুলি ব্যবহার করা এবং পরীক্ষক দৌড়বিদরা তাদের আহ্বান জানাতে একটি সম্মেলন নিয়োগ করার ক্ষেত্রে তুচ্ছ হত। শেষ অবধি, এই সীমাবদ্ধতাটি বাস্তবায়নের জন্য প্রত্যেকেই তাই করে - আপনার নিজের রানারকে রোল করুন, বা আপনার নিজের পরীক্ষার ক্লাসটি রোল করুন।
এইচডিভেন

1
@HDave, আমি মনে করি যে সঙ্গে আপনার সমাধান @PostConstructএবং @AfterClassঠিক যেমন একই আচরণ @Beforeএবং @After। প্রকৃতপক্ষে, আপনার পদ্ধতিগুলি প্রতিটি পরীক্ষার পদ্ধতির জন্য ডাকা হবে এবং একবারে পুরো ক্লাসের জন্য নয় (যেমন এসকো লুন্তোলা তার উত্তরে বলেছে যে প্রতিটি পরীক্ষার পদ্ধতির জন্য ক্লাসের একটি উদাহরণ তৈরি করা হয়েছে)। আমি আপনার সমাধানটির ইউটিলিটিটি দেখতে পাচ্ছি না (যদি আমি কিছু মিস না করি)
ম্যাগনুম 8787

1
এটি এখন 5 বছর ধরে সঠিকভাবে চলছে, তাই আমি ভাবছি আমার সমাধান কাজ করে।
এইচডিভ

13

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


2
কেবল সম্ভবত নয়, তবে ইউনাইট অবশ্যই পরীক্ষার কেসের একটি নতুন উদাহরণ তৈরি করবে। সুতরাং এটিই একমাত্র কারণ।
গেরদা

এটি কেবলমাত্র তাদের কাছে থাকার কারণ, তবে বাস্তবে জুনিট রানার টেস্টংয়ের পদ্ধতিতে পূর্বের টেস্ট এবং আফটার টেস্ট পদ্ধতি কার্যকর করার কাজ করতে পারে।
এইচডিএভ

টেস্টএনজি পরীক্ষা ক্লাসের একটি উদাহরণ তৈরি করে এবং ক্লাসের সমস্ত পরীক্ষার সাথে ভাগ করে দেয়? এটি পরীক্ষার মধ্যে পার্শ্ব-প্রতিক্রিয়াটিকে আরও ঝুঁকিপূর্ণ করে তোলে।
এসকো লুন্তটোলা

3

যদিও এটি মূল প্রশ্নের উত্তর দেবে না। এটি সুস্পষ্ট অনুসরণের উত্তর দেবে। কোনও নিয়ম কীভাবে তৈরি করা যায় যা কোনও ক্লাসের আগে এবং পরে এবং পরীক্ষার আগে এবং পরে কাজ করে।

আপনি এই প্যাটার্নটি ব্যবহার করতে পারেন তা অর্জন করতে:

@ClassRule
public static JPAConnection jpaConnection = JPAConnection.forUITest("my-persistence-unit");

@Rule
public JPAConnection.EntityManager entityManager = jpaConnection.getEntityManager();

এর আগে (ক্লাস) জেপিএসি কানেকশন একবার (ক্লাস) পরে সংযোগ তৈরি করে এটি এটি বন্ধ করে দেয়।

getEntityMangerএর একটি অভ্যন্তরীণ শ্রেণি প্রদান করে JPAConnectionযা জেপিএর সত্ত্বা ম্যানেজার প্রয়োগ করে এবং এর মধ্যে সংযোগ অ্যাক্সেস করতে পারে jpaConnection। এর আগে (পরীক্ষা) এর পরে এটি একটি লেনদেন শুরু হয় (পরীক্ষার পরে) এটি এটিকে আবার ফিরিয়ে দেয়।

এটি থ্রেড-নিরাপদ নয় তবে এটি হতে পারে।

নির্বাচিত কোড JPAConnection.class

package com.triodos.general.junit;

import com.triodos.log.Logger;
import org.jetbrains.annotations.NotNull;
import org.junit.rules.ExternalResource;

import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Persistence;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.metamodel.Metamodel;
import java.util.HashMap;
import java.util.Map;

import static com.google.common.base.Preconditions.checkState;
import static com.triodos.dbconn.DB2DriverManager.DRIVERNAME_TYPE4;
import static com.triodos.dbconn.UnitTestProperties.getDatabaseConnectionProperties;
import static com.triodos.dbconn.UnitTestProperties.getPassword;
import static com.triodos.dbconn.UnitTestProperties.getUsername;
import static java.lang.String.valueOf;
import static java.sql.Connection.TRANSACTION_READ_UNCOMMITTED;

public final class JPAConnectionExample extends ExternalResource {

  private static final Logger LOG = Logger.getLogger(JPAConnectionExample.class);

  @NotNull
  public static JPAConnectionExample forUITest(String persistenceUnitName) {
    return new JPAConnectionExample(persistenceUnitName)
        .setManualEntityManager();
  }

  private final String persistenceUnitName;
  private EntityManagerFactory entityManagerFactory;
  private javax.persistence.EntityManager jpaEntityManager = null;
  private EntityManager entityManager;

  private JPAConnectionExample(String persistenceUnitName) {
    this.persistenceUnitName = persistenceUnitName;
  }

  @NotNull
  private JPAConnectionExample setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
    return this;
  }

  @NotNull
  private JPAConnectionExample setManualEntityManager() {
    return setEntityManager(new RollBackAfterTestEntityManager());
  }


  @Override
  protected void before() {
    entityManagerFactory = Persistence.createEntityManagerFactory(persistenceUnitName, createEntityManagerProperties());
    jpaEntityManager = entityManagerFactory.createEntityManager();
  }

  @Override
  protected void after() {

    if (jpaEntityManager.getTransaction().isActive()) {
      jpaEntityManager.getTransaction().rollback();
    }

    if(jpaEntityManager.isOpen()) {
      jpaEntityManager.close();
    }
    // Free for garbage collection as an instance
    // of EntityManager may be assigned to a static variable
    jpaEntityManager = null;

    entityManagerFactory.close();
    // Free for garbage collection as an instance
    // of JPAConnection may be assigned to a static variable
    entityManagerFactory = null;
  }

  private Map<String,String> createEntityManagerProperties(){
    Map<String, String> properties = new HashMap<>();
    properties.put("javax.persistence.jdbc.url", getDatabaseConnectionProperties().getURL());
    properties.put("javax.persistence.jtaDataSource", null);
    properties.put("hibernate.connection.isolation", valueOf(TRANSACTION_READ_UNCOMMITTED));
    properties.put("hibernate.connection.username", getUsername());
    properties.put("hibernate.connection.password", getPassword());
    properties.put("hibernate.connection.driver_class", DRIVERNAME_TYPE4);
    properties.put("org.hibernate.readOnly", valueOf(true));

    return properties;
  }

  @NotNull
  public EntityManager getEntityManager(){
    checkState(entityManager != null);
    return entityManager;
  }


  private final class RollBackAfterTestEntityManager extends EntityManager {

    @Override
    protected void before() throws Throwable {
      super.before();
      jpaEntityManager.getTransaction().begin();
    }

    @Override
    protected void after() {
      super.after();

      if (jpaEntityManager.getTransaction().isActive()) {
        jpaEntityManager.getTransaction().rollback();
      }
    }
  }

  public abstract class EntityManager extends ExternalResource implements javax.persistence.EntityManager {

    @Override
    protected void before() throws Throwable {
      checkState(jpaEntityManager != null, "JPAConnection was not initialized. Is it a @ClassRule? Did the test runner invoke the rule?");

      // Safety-close, if failed to close in setup
      if (jpaEntityManager.getTransaction().isActive()) {
        jpaEntityManager.getTransaction().rollback();
        LOG.error("EntityManager encountered an open transaction at the start of a test. Transaction has been closed but should have been closed in the setup method");
      }
    }

    @Override
    protected void after() {
      checkState(jpaEntityManager != null, "JPAConnection was not initialized. Is it a @ClassRule? Did the test runner invoke the rule?");
    }

    @Override
    public final void persist(Object entity) {
      jpaEntityManager.persist(entity);
    }

    @Override
    public final <T> T merge(T entity) {
      return jpaEntityManager.merge(entity);
    }

    @Override
    public final void remove(Object entity) {
      jpaEntityManager.remove(entity);
    }

    @Override
    public final <T> T find(Class<T> entityClass, Object primaryKey) {
      return jpaEntityManager.find(entityClass, primaryKey);
    }

    @Override
    public final <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
      return jpaEntityManager.find(entityClass, primaryKey, properties);
    }

    @Override
    public final <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
      return jpaEntityManager.find(entityClass, primaryKey, lockMode);
    }

    @Override
    public final <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
      return jpaEntityManager.find(entityClass, primaryKey, lockMode, properties);
    }

    @Override
    public final <T> T getReference(Class<T> entityClass, Object primaryKey) {
      return jpaEntityManager.getReference(entityClass, primaryKey);
    }

    @Override
    public final void flush() {
      jpaEntityManager.flush();
    }

    @Override
    public final void setFlushMode(FlushModeType flushMode) {
      jpaEntityManager.setFlushMode(flushMode);
    }

    @Override
    public final FlushModeType getFlushMode() {
      return jpaEntityManager.getFlushMode();
    }

    @Override
    public final void lock(Object entity, LockModeType lockMode) {
      jpaEntityManager.lock(entity, lockMode);
    }

    @Override
    public final void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
      jpaEntityManager.lock(entity, lockMode, properties);
    }

    @Override
    public final void refresh(Object entity) {
      jpaEntityManager.refresh(entity);
    }

    @Override
    public final void refresh(Object entity, Map<String, Object> properties) {
      jpaEntityManager.refresh(entity, properties);
    }

    @Override
    public final void refresh(Object entity, LockModeType lockMode) {
      jpaEntityManager.refresh(entity, lockMode);
    }

    @Override
    public final void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
      jpaEntityManager.refresh(entity, lockMode, properties);
    }

    @Override
    public final void clear() {
      jpaEntityManager.clear();
    }

    @Override
    public final void detach(Object entity) {
      jpaEntityManager.detach(entity);
    }

    @Override
    public final boolean contains(Object entity) {
      return jpaEntityManager.contains(entity);
    }

    @Override
    public final LockModeType getLockMode(Object entity) {
      return jpaEntityManager.getLockMode(entity);
    }

    @Override
    public final void setProperty(String propertyName, Object value) {
      jpaEntityManager.setProperty(propertyName, value);
    }

    @Override
    public final Map<String, Object> getProperties() {
      return jpaEntityManager.getProperties();
    }

    @Override
    public final Query createQuery(String qlString) {
      return jpaEntityManager.createQuery(qlString);
    }

    @Override
    public final <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
      return jpaEntityManager.createQuery(criteriaQuery);
    }

    @Override
    public final <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
      return jpaEntityManager.createQuery(qlString, resultClass);
    }

    @Override
    public final Query createNamedQuery(String name) {
      return jpaEntityManager.createNamedQuery(name);
    }

    @Override
    public final <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
      return jpaEntityManager.createNamedQuery(name, resultClass);
    }

    @Override
    public final Query createNativeQuery(String sqlString) {
      return jpaEntityManager.createNativeQuery(sqlString);
    }

    @Override
    public final Query createNativeQuery(String sqlString, Class resultClass) {
      return jpaEntityManager.createNativeQuery(sqlString, resultClass);
    }

    @Override
    public final Query createNativeQuery(String sqlString, String resultSetMapping) {
      return jpaEntityManager.createNativeQuery(sqlString, resultSetMapping);
    }

    @Override
    public final void joinTransaction() {
      jpaEntityManager.joinTransaction();
    }

    @Override
    public final <T> T unwrap(Class<T> cls) {
      return jpaEntityManager.unwrap(cls);
    }

    @Override
    public final Object getDelegate() {
      return jpaEntityManager.getDelegate();
    }

    @Override
    public final void close() {
      jpaEntityManager.close();
    }

    @Override
    public final boolean isOpen() {
      return jpaEntityManager.isOpen();
    }

    @Override
    public final EntityTransaction getTransaction() {
      return jpaEntityManager.getTransaction();
    }

    @Override
    public final EntityManagerFactory getEntityManagerFactory() {
      return jpaEntityManager.getEntityManagerFactory();
    }

    @Override
    public final CriteriaBuilder getCriteriaBuilder() {
      return jpaEntityManager.getCriteriaBuilder();
    }

    @Override
    public final Metamodel getMetamodel() {
      return jpaEntityManager.getMetamodel();
    }
  }
}

2

দেখে মনে হয় যে প্রতিটি পরীক্ষার পদ্ধতির জন্য JUnit পরীক্ষার শ্রেণির একটি নতুন উদাহরণ তৈরি করে। এই কোড চেষ্টা করে দেখুন

public class TestJunit
{

    int count = 0;

    @Test
    public void testInc1(){
        System.out.println(count++);
    }

    @Test
    public void testInc2(){
        System.out.println(count++);
    }

    @Test
    public void testInc3(){
        System.out.println(count++);
    }
}

আউটপুট 0 0 0

এর অর্থ হ'ল যদি @ বিফোরক্লাস পদ্ধতিটি স্থিতিশীল না হয় তবে প্রতিটি পরীক্ষার পদ্ধতির আগে এটি কার্যকর করতে হবে এবং @ পূর্ব এবং @ পূর্বক্লাসের শব্দার্থবিজ্ঞানের মধ্যে পার্থক্য করার কোনও উপায় থাকবে না


এটা ঠিক নয় বলে মনে হচ্ছে যে ভাবে, এটা হয় যে ভাবে। প্রশ্নটি বহু বছর ধরে জিজ্ঞাসা করা হচ্ছে, এখানে উত্তরটি দেওয়া হয়েছে: মার্টিনফোলার.com
পল

1

দুটি ধরণের টিকা আছে:

  • পরীক্ষামূলক ক্লাসে একবার @ বিফোরক্লাস (@ আফটারক্লাস) ডাকা হয়
  • প্রতিটি পরীক্ষার আগে @ পূর্বে (এবং @ আফটার) কল করা হয়েছিল

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

এই উদাহরণ পরীক্ষায় @BeforeClass বনাম @ ব্যবহারের পূর্বে স্পষ্ট করা উচিত:

public class OrderTest {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("before class");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("after class");
    }

    @Before
    public void before() {
        System.out.println("before");
    }

    @After
    public void after() {
        System.out.println("after");
    }    

    @Test
    public void test1() {
        System.out.println("test 1");
    }

    @Test
    public void test2() {
        System.out.println("test 2");
    }
}

আউটপুট:

------------- স্ট্যান্ডার্ড আউটপুট ---------------
ক্লাসের আগে
আগে
পরীক্ষা 1
পরে
আগে
পরীক্ষা 2
পরে
ক্লাসের পরে
------------- ---------------- ---------------

19
আমি আপনার উত্তর অপ্রাসঙ্গিক মনে। আমি বিয়ারক্লাস এবং এর আগের শব্দার্থকগুলি জানি। এটি কেন স্থির হতে হবে তা ব্যাখ্যা করে না ...
রিপার 234

1
"এটি যতদূর আমি দেখছি কোনও যুক্তিসঙ্গত কারণে এটি আমার সমস্ত উদ্যোগকে অচল সদস্যদের হতে বাধ্য করে।" আমার উত্তরটি আপনাকে দেখাতে পারে যে আপনার উদ্যোগটি @ বিফোরক্লাসের পরিবর্তে @Before ব্যবহার করে অ স্থির হতে পারে
ডিএফএ

2
আমি ক্লাস শুরুর সময়, তবে অ স্থিতিশীল ভেরিয়েবলগুলিতে কেবল একবার একবার কিছু উদ্যোগ করতে চাই।
রিপার 234

আপনি JUnit দিয়ে পারবেন না, দুঃখিত। আপনাকে অবশ্যই একটি স্থির পরিবর্তনশীল ব্যবহার করতে হবে, কোনও উপায় নেই।
ডিএফএ

1
যদি সূচনাটি ব্যয়বহুল হয় তবে আপনি কেবল থিমটি করেছেন কিনা তা রেকর্ড করার জন্য কেবল একটি রাষ্ট্রীয় পরিবর্তনশীল রাখতে পারেন, এবং (এটি পরীক্ষা করুন এবং optionচ্ছিকভাবে) একটি @ পূর্ব পদ্ধতিতে আরআর সম্পাদন করুন ...
ব্লেয়ার কনরাড

0

জুনিয়ট 5 অনুসারে, মনে হয় পরীক্ষার পদ্ধতি অনুসারে একটি নতুন উদাহরণ তৈরি করার দর্শনটি কিছুটা senিলা হয়েছে। তারা এমন একটি টীকা যুক্ত করেছে যা পরীক্ষার ক্লাসটি একবারে ইনস্ট্যান্ট করবে। এই টীকাগুলি তাই @ বিটারআল / @ আফটারএল (@ বিফারডক্লাস / @ আফটারক্লাসের প্রতিস্থাপন) সাথে অ্যানোটেট করা পদ্ধতিগুলিকে অ স্থির থাকতে দেয়। সুতরাং, এর মতো একটি পরীক্ষা ক্লাস:

@TestInstance(Lifecycle.PER_CLASS)
class TestClass() {
    Object object;

    @BeforeAll
    void beforeAll() {
        object = new Object();
    }

    @Test
    void testOne() {
        System.out.println(object);
    }

    @Test
    void testTwo() {
        System.out.println(object);
    }
}

মুদ্রণ করবে:

java.lang.Object@799d4f69
java.lang.Object@799d4f69

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


-11

এই সমস্যাটি সমাধান করার জন্য কেবল পদ্ধতিটি পরিবর্তন করুন

public void setUpBeforeClass 

প্রতি

public static void setUpBeforeClass()

এবং এই পদ্ধতিতে সংজ্ঞায়িত সমস্ত static


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