জাভা 8 এর জাভা.টাইম এপিআইতে মশকরা সময়


90

জোকার সময়কে উপহাস করার জন্য একটি দুর্দান্ত ডেটটাইম ইউটিস.সেটকারেন্টমিলিসফিক্সড () রয়েছে

এটি পরীক্ষাগুলিতে খুব ব্যবহারিক।

জাভা 8 এর জাভা.টাইম এপিআই-তে কোনও সমতুল্য রয়েছে ?

উত্তর:


72

নিকটতম জিনিস হ'ল Clockবস্তু। আপনি যে কোনও সময় (বা সিস্টেমের বর্তমান সময় থেকে) চাইলে একটি ক্লক অবজেক্ট তৈরি করতে পারেন। সমস্ত ডেট.টাইম অবজেক্টের ওভারলোডেড nowপদ্ধতি রয়েছে যা বর্তমান সময়ের পরিবর্তে একটি ক্লক অবজেক্ট নেয়। সুতরাং আপনি একটি নির্দিষ্ট সময়ের সাথে একটি ঘড়ি ইনজেকশন করতে নির্ভরতা ইনজেকশন ব্যবহার করতে পারেন:

public class MyBean {
    private Clock clock;  // dependency inject
    ...
    public void process(LocalDate eventDate) {
      if (eventDate.isBefore(LocalDate.now(clock)) {
        ...
      }
    }
  }

আরও বিশদ জানতে ক্লক জাভাডক দেখুন


11
হ্যাঁ. বিশেষত, Clock.fixedপরীক্ষায় দরকারী, যখন Clock.systemবা Clock.systemUTCঅ্যাপ্লিকেশনটিতে ব্যবহৃত হতে পারে।
ম্যাট জনসন-পিন্ট

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

4
@bacar ক্লক বিমূর্ত ক্লাস হয়, আপনি আপনার নিজের পরীক্ষা ক্লক বাস্তবায়ন তৈরী করতে পারে
বিয়ারনে Boström

আমি বিশ্বাস করি এটিই আমরা শেষ করেছি।
বেকার

23

আমি Clock.fixedসৃষ্টিটি আড়াল করতে এবং পরীক্ষাগুলি সহজ করার জন্য একটি নতুন শ্রেণি ব্যবহার করেছি :

public class TimeMachine {

    private static Clock clock = Clock.systemDefaultZone();
    private static ZoneId zoneId = ZoneId.systemDefault();

    public static LocalDateTime now() {
        return LocalDateTime.now(getClock());
    }

    public static void useFixedClockAt(LocalDateTime date){
        clock = Clock.fixed(date.atZone(zoneId).toInstant(), zoneId);
    }

    public static void useSystemDefaultZoneClock(){
        clock = Clock.systemDefaultZone();
    }

    private static Clock getClock() {
        return clock ;
    }
}
public class MyClass {

    public void doSomethingWithTime() {
        LocalDateTime now = TimeMachine.now();
        ...
    }
}
@Test
public void test() {
    LocalDateTime twoWeeksAgo = LocalDateTime.now().minusWeeks(2);

    MyClass myClass = new MyClass();

    TimeMachine.useFixedClockAt(twoWeeksAgo);
    myClass.doSomethingWithTime();

    TimeMachine.useSystemDefaultZoneClock();
    myClass.doSomethingWithTime();

    ...
}

4
সমান্তরালভাবে বেশ কয়েকটি পরীক্ষা চালানো হয় এবং টাইমম্যাচিন ঘড়িটি পরিবর্তন করা হলে থ্রেড-সুরক্ষা সম্পর্কে কী বলা যায়?
youri

আপনাকে সময়টি সম্পর্কিত পদ্ধতিতে কল করার সময় পরীক্ষিত অবজেক্টে ঘড়িটি পাস করতে হবে এবং এটি ব্যবহার করতে হবে। এবং আপনি getClock()পদ্ধতিটি সরাতে এবং সরাসরি ক্ষেত্রটি ব্যবহার করতে পারেন । এই পদ্ধতিতে কোডের কয়েকটি লাইন ছাড়া কিছুই যুক্ত হয় না।
Deamon

4
ব্যাংকটাইম না টাইমমচিন?
ইমানুয়েল

11

আমি একটি ক্ষেত্র ব্যবহার

private Clock clock;

এবং তারপর

LocalDate.now(clock);

আমার প্রোডাকশন কোডে তারপরে আমি ক্লিপ.ফিক্সড () ব্যবহার করে ঘড়িটিকে উপহাস করার জন্য আমার ইউনিট পরীক্ষায় মকিতো ব্যবহার করেছি:

@Mock
private Clock clock;
private Clock fixedClock;

উপহাস:

fixedClock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
doReturn(fixedClock.instant()).when(clock).instant();
doReturn(fixedClock.getZone()).when(clock).getZone();

দৃ :়তা:

assertThat(expectedLocalDateTime, is(LocalDate.now(fixedClock)));

9

আমি Clockআপনার প্রোডাকশন কোডকে ক্লিটার্স ব্যবহার করে দেখতে পাই।

আপনি আপনার পরীক্ষার কোডে স্থির পদ্ধতি আমন্ত্রণগুলি উপহাস করতে JMockit বা পাওয়ারমক ব্যবহার করতে পারেন । জেমকিতের সাথে উদাহরণ:

@Test
public void testSth() {
  LocalDate today = LocalDate.of(2000, 6, 1);

  new Expectations(LocalDate.class) {{
      LocalDate.now(); result = today;
  }};

  Assert.assertEquals(LocalDate.now(), today);
}

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

যদিও আপনার যদি লিগ্যাসি কোডটি মোকাবেলা করতে হয় তবে আপনি অবশ্যই স্থির বিদ্রূপ ব্যবহার করতে পারেন।


4
"লিগ্যাসি কোডের জন্য স্থির বিদ্রূপ ব্যবহার করা" মন্তব্যটির জন্য +1। সুতরাং নতুন কোডের জন্য, নির্ভরতা ইনজেকশনে ঝুঁকতে এবং একটি ঘড়ি ইনজেকশনের জন্য উত্সাহিত করুন (পরীক্ষার জন্য নির্দিষ্ট ঘড়ি, উত্পাদন রানটাইমের জন্য সিস্টেম ক্লক))
ডেভিড গ্রুমস

1

LocalDateপরিবর্তে আমার প্রয়োজন LocalDateTime
এই কারণে আমি নিম্নলিখিত ইউটিলিটি ক্লাস তৈরি করেছি:

public final class Clock {
    private static long time;

    private Clock() {
    }

    public static void setCurrentDate(LocalDate date) {
        Clock.time = date.toEpochDay();
    }

    public static LocalDate getCurrentDate() {
        return LocalDate.ofEpochDay(getDateMillis());
    }

    public static void resetDate() {
        Clock.time = 0;
    }

    private static long getDateMillis() {
        return (time == 0 ? LocalDate.now().toEpochDay() : time);
    }
}

এবং এর জন্য ব্যবহারের মতো:

class ClockDemo {
    public static void main(String[] args) {
        System.out.println(Clock.getCurrentDate());

        Clock.setCurrentDate(LocalDate.of(1998, 12, 12));
        System.out.println(Clock.getCurrentDate());

        Clock.resetDate();
        System.out.println(Clock.getCurrentDate());
    }
}

আউটপুট:

2019-01-03
1998-12-12
2019-01-03

সব সৃষ্টি প্রতিস্থাপিত LocalDate.now()করার Clock.getCurrentDate()প্রকল্পে।

কারণ এটি স্প্রিং বুট অ্যাপ্লিকেশন। testপ্রোফাইল কার্যকর করার আগে সমস্ত পরীক্ষার জন্য একটি পূর্বনির্ধারিত তারিখ সেট করা হয়:

public class TestProfileConfigurer implements ApplicationListener<ApplicationPreparedEvent> {
    private static final LocalDate TEST_DATE_MOCK = LocalDate.of(...);

    @Override
    public void onApplicationEvent(ApplicationPreparedEvent event) {
        ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
        if (environment.acceptsProfiles(Profiles.of("test"))) {
            Clock.setCurrentDate(TEST_DATE_MOCK);
        }
    }
}

এবং স্প্রিং.ফ্যাক্টরিগুলিতে যুক্ত করুন :

org.springframework.context. ApplicationListener = com.init.TestProfileConfigurer


1

ইজিমকের সাথে জাভা 8 ওয়েব অ্যাপ্লিকেশনটিতে জুনিট পরীক্ষার উদ্দেশ্যে একটি নির্দিষ্ট তারিখে বর্তমান সিস্টেমের সময়কে ওভাররাইড করার একটি কার্যকরী উপায়

জোডা টাইম অবশ্যই দুর্দান্ত (আপনাকে ধন্যবাদ স্টিফেন, ব্রায়ান, আপনি আমাদের বিশ্বকে আরও ভাল জায়গা করে নিয়েছেন) তবে আমাকে এটি ব্যবহারের অনুমতি দেওয়া হয়নি।

কিছু পরীক্ষা-নিরীক্ষার পরে অবশেষে ইজিমকের সাহায্যে জাভা 8 এর জাভা.টাইম এপিআই-তে নির্দিষ্ট তারিখে সময়কে উপহাস করার উপায় নিয়ে এসেছি

  • জোডা টাইম এপিআই ছাড়া
  • পাওয়ারমক ছাড়াই।

এখানে যা করা দরকার তা এখানে:

পরীক্ষিত শ্রেণিতে কী করা দরকার

ধাপ 1

java.time.Clockপরীক্ষিত শ্রেণিতে একটি নতুন বৈশিষ্ট্য যুক্ত করুন MyServiceএবং নিশ্চিত করুন যে নতুন বৈশিষ্ট্যটি ইনস্ট্যান্টেশন ব্লক বা কনস্ট্রাক্টরের সাথে ডিফল্ট মানগুলিতে সঠিকভাবে শুরু হবে:

import java.time.Clock;
import java.time.LocalDateTime;

public class MyService {
  // (...)
  private Clock clock;
  public Clock getClock() { return clock; }
  public void setClock(Clock newClock) { clock = newClock; }

  public void initDefaultClock() {
    setClock(
      Clock.system(
        Clock.systemDefaultZone().getZone() 
        // You can just as well use
        // java.util.TimeZone.getDefault().toZoneId() instead
      )
    );
  }
  { initDefaultClock(); } // initialisation in an instantiation block, but 
                          // it can be done in a constructor just as well
  // (...)
}

ধাপ ২

clockপদ্ধতিটিতে নতুন অ্যাট্রিবিউট ইনজেক্ট করুন যা বর্তমান তারিখ-সময়ের জন্য কল করে। উদাহরণস্বরূপ, আমার ক্ষেত্রে আমাকে ডাটাবেসে সঞ্চিত তারিখটি আগে ঘটেছিল কিনা তা যাচাই বাছাই করতে হয়েছিল LocalDateTime.now(), যা আমি এর সাথে প্রতিস্থাপন LocalDateTime.now(clock)করেছি:

import java.time.Clock;
import java.time.LocalDateTime;

public class MyService {
  // (...)
  protected void doExecute() {
    LocalDateTime dateToBeCompared = someLogic.whichReturns().aDate().fromDB();
    while (dateToBeCompared.isBefore(LocalDateTime.now(clock))) {
      someOtherLogic();
    }
  }
  // (...) 
}

পরীক্ষা ক্লাসে কী করা দরকার

ধাপ 3

পরীক্ষার ক্লাসে, একটি মক ক্লক অবজেক্ট তৈরি করুন এবং পরীক্ষিত পদ্ধতিটি কল করার ঠিক আগে পরীক্ষিত শ্রেণীর উদাহরণে এটিকে ইনজেক্ট করুন doExecute(), তারপরে এটিকে ঠিক আবার পিছনে পুনরায় সেট করুন: এর মতো:

import java.time.Clock;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import org.junit.Test;

public class MyServiceTest {
  // (...)
  private int year = 2017;  // Be this a specific 
  private int month = 2;    // date we need 
  private int day = 3;      // to simulate.

  @Test
  public void doExecuteTest() throws Exception {
    // (...) EasyMock stuff like mock(..), expect(..), replay(..) and whatnot
 
    MyService myService = new MyService();
    Clock mockClock =
      Clock.fixed(
        LocalDateTime.of(year, month, day, 0, 0).toInstant(OffsetDateTime.now().getOffset()),
        Clock.systemDefaultZone().getZone() // or java.util.TimeZone.getDefault().toZoneId()
      );
    myService.setClock(mockClock); // set it before calling the tested method
 
    myService.doExecute(); // calling tested method 

    myService.initDefaultClock(); // reset the clock to default right afterwards with our own previously created method

    // (...) remaining EasyMock stuff: verify(..) and assertEquals(..)
    }
  }

এটি ডিবাগ মোডে দেখুন এবং আপনি দেখতে পাবেন 2017 ফেব্রুয়ারির 3 তারিখটি সঠিকভাবে ইনজেকশনের myServiceসাথে তুলনা নির্দেশে ব্যবহৃত হয়েছে এবং তারপরে সঠিকভাবে বর্তমান তারিখে পুনরায় সেট করা হয়েছে initDefaultClock()


0

এই উদাহরণটি তাত্ক্ষণিক এবং স্থানীয় সময়কে কীভাবে সংযুক্ত করতে হয় তাও দেখায় ( রূপান্তরটির সাথে ইস্যুগুলির বিস্তারিত ব্যাখ্যা )

পরীক্ষার অধীনে একটি ক্লাস

import java.time.Clock;
import java.time.LocalTime;

public class TimeMachine {

    private LocalTime from = LocalTime.MIDNIGHT;

    private LocalTime until = LocalTime.of(6, 0);

    private Clock clock = Clock.systemDefaultZone();

    public boolean isInInterval() {

        LocalTime now = LocalTime.now(clock);

        return now.isAfter(from) && now.isBefore(until);
    }

}

একটি গ্রোভী পরীক্ষা

import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized

import java.time.Clock
import java.time.Instant

import static java.time.ZoneOffset.UTC
import static org.junit.runners.Parameterized.Parameters

@RunWith(Parameterized)
class TimeMachineTest {

    @Parameters(name = "{0} - {2}")
    static data() {
        [
            ["01:22:00", true,  "in interval"],
            ["23:59:59", false, "before"],
            ["06:01:00", false, "after"],
        ]*.toArray()
    }

    String time
    boolean expected

    TimeMachineTest(String time, boolean expected, String testName) {
        this.time = time
        this.expected = expected
    }

    @Test
    void test() {
        TimeMachine timeMachine = new TimeMachine()
        timeMachine.clock = Clock.fixed(Instant.parse("2010-01-01T${time}Z"), UTC)
        def result = timeMachine.isInInterval()
        assert result == expected
    }

}

0

একটি বসন্ত বুট পরীক্ষার জন্য পাওয়ারমকিতোর সাহায্যে আপনি উপহাস করতে পারেন ZonedDateTime। আপনার নিম্নলিখিতগুলি দরকার।

টিকা

পরীক্ষার শ্রেণিতে আপনাকে পরিষেবাটি প্রস্তুত করতে হবে যা ব্যবহার করে ZonedDateTime

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({EscalationService.class})
@SpringBootTest
public class TestEscalationCases {
  @Autowired
  private EscalationService escalationService;
  //...
}

পরীক্ষা ক্ষেত্রে

পরীক্ষায় আপনি একটি পছন্দসই সময় প্রস্তুত করতে পারেন, এবং পদ্ধতি কলের প্রতিক্রিয়াতে এটি পেতে পারেন।

  @Test
  public void escalateOnMondayAt14() throws Exception {
    ZonedDateTime preparedTime = ZonedDateTime.now();
    preparedTime = preparedTime.with(DayOfWeek.MONDAY);
    preparedTime = preparedTime.withHour(14);
    PowerMockito.mockStatic(ZonedDateTime.class);
    PowerMockito.when(ZonedDateTime.now(ArgumentMatchers.any(ZoneId.class))).thenReturn(preparedTime);
    // ... Assertions 
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.