সংবেদনশীল কোডটি পরীক্ষার জন্য জাভা সিস্টেম। বর্তমান টাইমমিলিসকে ওভাররাইড করুন


129

System.currentTimeMillisহোস্ট মেশিনে ম্যানুয়ালি সিস্টেমের ঘড়ি পরিবর্তনের পরিবর্তে বর্তমান সময়কে ওভাররাইড করার জন্য কোডে বা জেভিএম আর্গুমেন্টের সাথে কি কোনও উপায় আছে ?

একটু ব্যাকগ্রাউন্ড:

আমাদের কাছে এমন একটি সিস্টেম রয়েছে যা প্রচুর অ্যাকাউন্টিং কাজ চালায় যা তাদের বর্তমান যুক্তিগুলির বেশিরভাগ বর্তমান তারিখের চারদিকে ঘোরে (অর্থাত্ মাসের প্রথম, বছরের প্রথম দিন ইত্যাদি)

দুর্ভাগ্যক্রমে, প্রচুর লিগ্যাসি কোডগুলি ফাংশনগুলিকে কল করে যেমন new Date()বা Calendar.getInstance()উভয়ই শেষ পর্যন্ত ডাকে System.currentTimeMillis

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

সুতরাং আমার প্রশ্নটি হ'ল:

ফেরত দেওয়া কি ওভাররাইড করার কোনও উপায় আছে System.currentTimeMillis? উদাহরণস্বরূপ, JVM কে সেই পদ্ধতি থেকে ফিরে আসার আগে কিছু অফসেট স্বয়ংক্রিয়ভাবে যোগ বা বিয়োগ করতে বলুন?

আগাম ধন্যবাদ!


1
এটি আর প্রাসঙ্গিক কিনা তা আমি জানি না, তবে এসপেক্টজে দিয়ে এটি অর্জনের জন্য আরও একটি পদ্ধতি রয়েছে, আমার উত্তরটি এখানে দেখুন: stackoverflow.com/questions/18239859/…
ন্যানডোর এলিড ফেকেট

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

1
@ ক্যালবার্জ অ্যাসপেক্টজ-এর একটি দুর্দান্ত বৈশিষ্ট্য হ'ল সরাসরি বাইটকোডে পরিচালিত হয়, কাজ করার জন্য এটির মূল উত্স কোডের প্রয়োজন হয় না।
ন্যানডোর এলিড ফেকেট 21

@ ন্যানডোরএলডিফিকেট ইঙ্গিতটির জন্য আপনাকে অনেক ধন্যবাদ আমি বিবিসিপি বাইটোকোড-স্তরের উপকরণ (বিশেষত জেডিকে ক্লাসের উপকরণ) সম্পর্কে অজানা ছিলাম। এটি আমার কিছুটা সময় নিয়েছে তবে আমি বুঝতে পেরেছিলাম যে আমার প্রয়োজন অনুসারে (আর ওভাররাইড সিস্টেমের জন্য) আরডি.জারের একটি সংকলন-সময় বুননের পাশাপাশি নন-জেডিকি ক্লাসগুলির একটি লোড-টাইম বয়ন উভয়কেই পেয়েছিলাম। কারেন্টটাইমমিলিস () এবং System.nanoTime ())।
ক্লেবার্জ

@ ক্যালবার্জ জেআরই ক্লাসের মাধ্যমে বুনার জন্য আমার আরও একটি উত্তর রয়েছে , আপনি এটিও পরীক্ষা করে দেখতে পারেন।
নন্দর এলড ফেকেট

উত্তর:


115

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

এটি প্রায় সন্ধানের সাথে স্বয়ংক্রিয়ভাবে তৈরি হতে পারে এবং সিঙ্গলটন সংস্করণটির জন্য প্রতিস্থাপন করা যেতে পারে:

  • Calendar.getInstance()সঙ্গে প্রতিস্থাপন Clock.getInstance().getCalendarInstance()
  • new Date()সঙ্গে প্রতিস্থাপনClock.getInstance().newDate()
  • System.currentTimeMillis()সঙ্গে প্রতিস্থাপনClock.getInstance().currentTimeMillis()

(ইত্যাদি হিসাবে)

একবার আপনি এই প্রথম পদক্ষেপটি গ্রহণ করার পরে, আপনি একবারে ডিআই দিয়ে সিঙ্গলটন প্রতিস্থাপন করতে পারেন।


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

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

4
@ কুমারী 47: আমি মনে করি আমাদের সাথে একমত হতে হবে না। কোডটিকে দূষণকারী হিসাবে আমি "আপনার নির্ভরতা স্পষ্টভাবে উল্লেখ করে" দেখছি না - আমি কোডটি পরিষ্কার করার প্রাকৃতিক উপায় হিসাবে দেখছি। এবং অজানাভাবে "পুরোপুরি গ্রহণযোগ্য" হিসাবে স্ট্যাটিক কলগুলির মাধ্যমে সেই নির্ভরতাগুলি লুকিয়ে দেখছি না।
জন স্কিটি

26
আপডেট করুন জাভা 8-এ নির্মিত নতুন জাভা.টাইম প্যাকেজটিতেjava.time.Clock "প্রয়োজনীয় ঘড়ি যেমন প্রয়োজন হয় তখন প্লাগ ইন করার অনুমতি দেওয়ার জন্য" শ্রেণি অন্তর্ভুক্ত থাকে ।
তুলসী বাউরক

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

78

TL; ড

হোস্ট মেশিনে ম্যানুয়ালি সিস্টেমের ঘড়িটি পরিবর্তনের পরিবর্তে সিস্টেমকন্ট্রেন্টটাইমমিলিসের মাধ্যমে উপস্থাপিত বর্তমান সময়কে ওভাররাইড করার জন্য কোডে বা জেভিএম আর্গুমেন্টের সাথে কি কোনও উপায় আছে?

হ্যাঁ.

Instant.now( 
    Clock.fixed( 
        Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
    )
)

Clock জাভা.টাইমে

ভুল -তারিখ-সময়ের মানগুলির সাথে পরীক্ষার সুবিধার্থে আমাদের প্লাগেবল ঘড়ি প্রতিস্থাপনের সমস্যার নতুন সমাধান রয়েছে । Java.time প্যাকেজ মধ্যে জাভা 8 একটি বিমূর্ত বর্গ অন্তর্ভুক্ত java.time.Clock, একটি সুনির্দিষ্ট উদ্দেশ্য সঙ্গে:

যখন প্রয়োজন হয় তখন বিকল্প ঘড়িগুলি প্লাগ ইন করার অনুমতি দেয়

আপনি নিজের বাস্তবায়নের জন্য প্লাগ ইন Clockকরতে পারেন, যদিও আপনি সম্ভবত আপনার চাহিদা মেটাতে ইতিমধ্যে তৈরি একটি খুঁজে পেতে পারেন। আপনার সুবিধার জন্য, জাভা.টাইমে বিশেষ বাস্তবায়ন উপার্জনের স্থিত পদ্ধতি অন্তর্ভুক্ত। এই বিকল্প বাস্তবায়ন পরীক্ষার সময় মূল্যবান হতে পারে।

পরিবর্তিত ক্যাডেন্স

বিভিন্ন tick…পদ্ধতি এমন ঘড়ি তৈরি করে যা বর্তমান মুহুর্তটিকে আলাদা আলাদা ক্যাডেন্সের সাথে বাড়িয়ে তোলে।

ডিফল্ট Clockসময় যেমন ঘন ঘন আপডেট করা যেমন রিপোর্ট মিলিসেকেন্ড যেমন জরিমানা হিসাবে জাভা 8 এবং জাভা 9 ন্যানোসেকেন্ড (আপনার হার্ডওয়ার উপর নির্ভর করে)। আপনি সত্যিকারের বর্তমান মুহুর্তটিকে ভিন্ন গ্রানুলারিটির সাথে প্রতিবেদন করার জন্য বলতে পারেন।

  • tickSeconds - পুরো সেকেন্ডে বৃদ্ধি
  • tickMinutes - পুরো মিনিটে বৃদ্ধি
  • tick- পাস Durationযুক্তি দ্বারা বৃদ্ধি ।

মিথ্যা ঘড়ি

কিছু ঘড়ি মিথ্যা বলতে পারে, হোস্ট ওএসের হার্ডওয়্যার ক্লকের চেয়ে আলাদা ফলাফল তৈরি করে।

  • fixed - একক অপরিবর্তনীয় (অ-বর্ধমান) মুহুর্তটিকে বর্তমান মুহুর্ত হিসাবে প্রতিবেদন করে।
  • offset- বর্তমান মুহুর্তের প্রতিবেদন করে তবে পাস হওয়া Durationযুক্তি দ্বারা স্থানান্তরিত ।

উদাহরণস্বরূপ, এই বছরের প্রথম দিকের ক্রিসমাসের প্রথম মুহূর্তে লক করুন। অন্য কথায়, যখন সান্তা এবং তার নীলকান্তি তাদের প্রথম থামবে । নিকটতম সময় অঞ্চল আজকাল মনে করা হয় Pacific/Kiritimati+14:00

LocalDate ld = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate xmasThisYear = MonthDay.of( Month.DECEMBER , 25 ).atYear( ld.getYear() );
ZoneId earliestXmasZone = ZoneId.of( "Pacific/Kiritimati" ) ;
ZonedDateTime zdtEarliestXmasThisYear = xmasThisYear.atStartOfDay( earliestXmasZone );
Instant instantEarliestXmasThisYear = zdtEarliestXmasThisYear.toInstant();
Clock clockEarliestXmasThisYear = Clock.fixed( instantEarliestXmasThisYear , earliestXmasZone );

সর্বদা একই মুহূর্তটি ফিরে আসতে সেই নির্দিষ্ট স্থির ঘড়িটি ব্যবহার করুন। আমরা কিরীটিমতিতে ক্রিসমাস দিবসের প্রথম মুহূর্তটি পাই , ইউটিসি চৌদ্দ ঘন্টা আগে দেওয়াল-ঘড়ির সময় দেখায় , ২৪ শে ডিসেম্বর এর পূর্বের তারিখের দশটায় AM

Instant instant = Instant.now( clockEarliestXmasThisYear );
ZonedDateTime zdt = ZonedDateTime.now( clockEarliestXmasThisYear );

instant.toString (): 2016-12-24T10: 00: 00Z

zdt.toString (): 2016-12-25T00: 00 + 14: 00 [প্রশান্ত মহাসাগর / কিরীটিমতি]

IdeOne.com এ লাইভ কোড দেখুন ।

সত্য সময়, বিভিন্ন সময় অঞ্চল

Clockবাস্তবায়নের মাধ্যমে কোন সময় অঞ্চল নির্ধারিত হয়েছে তা আপনি নিয়ন্ত্রণ করতে পারেন । এটি কিছু পরীক্ষায় কার্যকর হতে পারে। তবে আমি এটি উত্পাদন কোডে প্রস্তাব দিই না, যেখানে আপনার সর্বদা theচ্ছিক ZoneIdবা ZoneOffsetযুক্তিগুলি স্পষ্টভাবে নির্দিষ্ট করা উচিত ।

আপনি ইউটিসিটিকে ডিফল্ট অঞ্চল হিসাবে নির্দিষ্ট করতে পারেন।

ZonedDateTime zdtClockSystemUTC = ZonedDateTime.now ( Clock.systemUTC () );

আপনি যে কোনও নির্দিষ্ট সময় অঞ্চল নির্দিষ্ট করতে পারেন। একটি নির্দিষ্ট করুন সঠিক সময় অঞ্চল নাম এর বিন্যাসে continent/regionযেমন America/Montreal, Africa/Casablancaঅথবা Pacific/Auckland। কখনও যেমন 3-4 চিঠি সংক্ষেপ ব্যবহার ESTবা ISTহিসাবে তারা না সত্য সময় অঞ্চল, না মান, এবং এমনকি অনন্য নয় (!)।

ZonedDateTime zdtClockSystem = ZonedDateTime.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );

আপনি জেভিএমের বর্তমান ডিফল্ট টাইম অঞ্চল নির্দিষ্ট Clockকোনও অবজেক্টের জন্য ডিফল্ট হওয়া উচিত তা নির্দিষ্ট করতে পারেন ।

ZonedDateTime zdtClockSystemDefaultZone = ZonedDateTime.now ( Clock.systemDefaultZone () );

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

System.out.println ( "zdtClockSystemUTC.toString(): " + zdtClockSystemUTC );
System.out.println ( "zdtClockSystem.toString(): " + zdtClockSystem );
System.out.println ( "zdtClockSystemDefaultZone.toString(): " + zdtClockSystemDefaultZone );

America/Los_Angeles এই কোডটি চালিত কম্পিউটারে জেভিএম বর্তমান ডিফল্ট অঞ্চল ছিল।

zdtClockSystemUTC.toString (): 2016-12-31T20: 52: 39.688Z

zdtClockSystem.toString (): 2016-12-31T15: 52: 39.750-05: 00 [আমেরিকা / মন্ট্রিল]

zdtClockSystemDefaultZone.toString (): 2016-12-31T12: 52: 39.762-08: 00 [আমেরিকা / লস_এঞ্জেলস]

Instantবর্গ সংজ্ঞা দ্বারা ইউটিসি সর্বদা। সুতরাং এই তিনটি অঞ্চল-সম্পর্কিত Clockব্যবহারের ঠিক একই প্রভাব রয়েছে।

Instant instantClockSystemUTC = Instant.now ( Clock.systemUTC () );
Instant instantClockSystem = Instant.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Instant instantClockSystemDefaultZone = Instant.now ( Clock.systemDefaultZone () );

ইনস্ট্যান্টক্লকসিস্টমুটসি.টোস্ট্রিং (): 2016-12-31T20: 52: 39.763Z

ইনস্ট্যান্টক্লকসিস্টেম.টোস্ট্রিং (): 2016-12-31T20: 52: 39.763Z

ইনস্ট্যান্টক্লকসিস্টেমডিফল্টজোন.টো স্ট্রিং (): 2016-12-31T20: 52: 39.763Z

ডিফল্ট ঘড়ি

এর জন্য ডিফল্টরূপে প্রয়োগ করা বাস্তবায়নের মাধ্যমে Instant.nowফিরে আসে Clock.systemUTC()। আপনি যখন কোনও নির্দিষ্ট না করেন তখন এটি ব্যবহার করা হয় Clockপ্রি-রিলিজ জাভা 9 এর জন্য কোডের জন্যInstant.now নিজের জন্য দেখুন ।

public static Instant now() {
    return Clock.systemUTC().instant();
}

Clockজন্য ডিফল্ট OffsetDateTime.nowএবং ZonedDateTime.nowহয় Clock.systemDefaultZone()উত্স কোড দেখুন ।

public static ZonedDateTime now() {
    return now(Clock.systemDefaultZone());
}

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


জাভা.টাইম সম্পর্কে

Java.time ফ্রেমওয়ার্ক জাভা 8 এবং পরে পাতাটা করা হয়। এই ক্লাসগুলি , & , এর মতো সমস্যাযুক্ত পুরানো উত্তরাধিকারের তারিখ-সময়ের ক্লাসগুলিকে সহায়তা করে ।java.util.DateCalendarSimpleDateFormat

আরও জানতে, ওরাকল টিউটোরিয়ালটি দেখুন । এবং অনেক উদাহরণ এবং ব্যাখ্যার জন্য স্ট্যাক ওভারফ্লো অনুসন্ধান করুন। স্পেসিফিকেশনটি জেএসআর 310

Joda-টাইম প্রকল্প, এখন রক্ষণাবেক্ষণ মোড , মাইগ্রেশনে উপদেশ java.time ক্লাস।

আপনি আপনার ডাটাবেসের সাথে জাভা.টাইম অবজেক্টগুলি সরাসরি বিনিময় করতে পারেন । জেডিবিসি ৪.২ বা তারপরের সাথে অনুগত একটি জেডিবিসি ড্রাইভার ব্যবহার করুন । স্ট্রিংগুলির দরকার নেই, ক্লাসের প্রয়োজন নেই । হাইবারনেট 5 এবং জেপিএ 2.2 সমর্থন জাভা.টাইমjava.sql.*

জাভা.টাইম ক্লাস কোথায় পাবেন?


এটিই সঠিক উত্তর
ভারাল

42

যেমন জোন স্কিট বলেছেন :

"জাডা টাইম ব্যবহার করুন" "জাভা.ইটিল.ডেট / ক্যালেন্ডারের সাহায্যে আমি কীভাবে এক্স অর্জন করব?" জড়িত যে কোনও প্রশ্নের জবাব দেওয়ার প্রায় সবসময়ই সেরা উত্তর?

সুতরাং এখানে চলে যায় (ধরে নেওয়া যায় যে আপনি কেবল আপনার সমস্তটি প্রতিস্থাপন new Date()করেছেন new DateTime().toDate())

//Change to specific time
DateTimeUtils.setCurrentMillisFixed(millis);
//or set the clock to be a difference from system time
DateTimeUtils.setCurrentMillisOffset(millis);
//Reset to system time
DateTimeUtils.setCurrentMillisSystem();

আপনি যদি কোনও লাইব্রেরিটি ইন্টারফেসযুক্ত আমদানি করতে চান (নীচে জনের মন্তব্য দেখুন), আপনি কেবল প্রিভায়্লারের ঘড়িটি ব্যবহার করতে পারেন যা বাস্তবায়ন পাশাপাশি মানক ইন্টারফেস সরবরাহ করবে। পুরো জারটি মাত্র 96 কেবি, তাই এটি ব্যাংকটি ভাঙ্গা উচিত নয় ...


13
না, আমি এটি সুপারিশ করব না - এটি আপনাকে সত্যিকারের প্রতিস্থাপনযোগ্য ঘড়ির দিকে নিয়ে যায় না; এটি আপনাকে স্ট্যাটিক্স জুড়ে রাখে। জোডা টাইম ব্যবহার করা অবশ্যই একটি ভাল ধারণা, তবে আমি এখনও একটি ক্লক ইন্টারফেস বা অনুরূপ সাথে যেতে চাই।
জন স্কিটি

@ জোন: সত্য - পরীক্ষার জন্য এটি ঠিক আছে তবে ইন্টারফেস থাকা ভাল।
স্টিফেন

5
@ জন: আপনি যদি সময় নির্ধারিত কোড যা ইতিমধ্যে জোডটাইম ব্যবহার করে তা পরীক্ষা করতে চান তবে এটি একটি মসৃণ এবং আইএমএইচও নিখুঁত এবং সহজ উপায়। জোদাটাইম দিয়ে ইতিমধ্যে আপনার জন্য যদি সমস্ত কিছু সমাধান করা হয়ে থাকে, তবে আর একটি বিমূর্ত স্তর / কাঠামো প্রবর্তন করে চাকাটিকে পুনর্বহাল করার চেষ্টা করা উপায় নয়।
স্টিফান হ্যাবারেল

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

2
@ স্টেফানহবারল: এমন অনেকগুলি বিষয় রয়েছে যা কঠোরভাবে "প্রয়োজনীয়" নয় - তবে আমি যা বলছি তা ইতিমধ্যে বিদ্যমান নির্ভরতা সুস্পষ্ট এবং বিচ্ছিন্নতায় আরও সহজে পরীক্ষামূলকভাবে তৈরি করা। স্ট্যাটিক্সের সাথে সিস্টেমের সময়টিকে নষ্ট করার ক্ষেত্রে স্ট্যাটিক্সের সমস্ত সাধারণ সমস্যা রয়েছে - এটি কোনও কারণ ছাড়াই বৈশ্বিক রাষ্ট্র । মাইক পরীক্ষারযোগ্য কোডটি লেখার জন্য একটি উপায় চেয়েছিল যা বর্তমান তারিখ এবং সময় ব্যবহার করে used আমি এখনও বিশ্বাস করি যে আমার পরামর্শটি কার্যকরভাবে একটি স্ট্যাটিকের সাথে ঝাঁকুনির চেয়ে পরিষ্কার (এবং নির্ভরতা আরও পরিষ্কার করে তোলে)।
জন স্কিটে

15

কিছু ডেটফ্যাক্টরি প্যাটার্ন ব্যবহার করা দুর্দান্ত বলে মনে হচ্ছে, এটি আপনার নিয়ন্ত্রণ করতে পারে না এমন লাইব্রেরিগুলিকে কভার করে না - কল্পনা করুন ভেরিফিকেশন টীকা @ পাসপোর্ট বাস্তবায়নের সাথে সিস্টেমটি।

এজন্য আমরা সরাসরি সিস্টেমের সময়টিকে উপহাস করার জন্য jmockit ব্যবহার করি:

import mockit.Mock;
import mockit.MockClass;
...
@MockClass(realClass = System.class)
public static class SystemMock {
    /**
     * Fake current time millis returns value modified by required offset.
     *
     * @return fake "current" millis
     */
    @Mock
    public static long currentTimeMillis() {
        return INIT_MILLIS + offset + millisSinceClassInit();
    }
}

Mockit.setUpMock(SystemMock.class);

মিলিসের মূল আনমকড মানটি পাওয়া সম্ভব নয় বলে আমরা এর পরিবর্তে ন্যানো টাইমার ব্যবহার করি - এটি প্রাচীর ঘড়ির সাথে সম্পর্কিত নয়, তবে আপেক্ষিক সময় এখানে যথেষ্ট:

// runs before the mock is applied
private static final long INIT_MILLIS = System.currentTimeMillis();
private static final long INIT_NANOS = System.nanoTime();

private static long millisSinceClassInit() {
    return (System.nanoTime() - INIT_NANOS) / 1000000;
}

নথিভুক্ত সমস্যা আছে, হটস্পটের সাথে বেশ কয়েকটি কল করার পরে সময়টি স্বাভাবিক হয়ে যায় - এখানে ইস্যু প্রতিবেদনটি দেওয়া হয়েছে: http://code.google.com/p/jmockit/issues/detail?id=43

এটি কাটিয়ে উঠতে আমাদের একটি নির্দিষ্ট হটস্পট অপটিমাইজেশন চালু করতে হবে - এই যুক্তি দিয়ে জেভিএম চালান -XX:-Inline

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

সম্পূর্ণ গল্পটি আমার ব্লগ পোস্টে এখানে রয়েছে: http://virgo47.wordpress.com/2012/06/22/changing-system-time-in-java/

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

জুলাই ২০১৪ সম্পাদনা করুন: জেএমকিট ইদানীং অনেক পরিবর্তন হয়েছে এবং এটি সঠিকভাবে ব্যবহার করতে আপনি JMockit 1.0 ব্যবহার করতে বাধ্য (আইআইআরসি)। অবশ্যই নতুন সংস্করণে আপগ্রেড করতে পারে না যেখানে ইন্টারফেস সম্পূর্ণ আলাদা। আমি কেবল প্রয়োজনীয় জিনিসগুলি ইনলাইন করার বিষয়ে ভাবছিলাম, তবে আমাদের নতুন প্রকল্পগুলিতে আমাদের এই জিনিসটির প্রয়োজন নেই বলে আমি এই জিনিসটি একেবারেই বিকাশ করছি না।


1
আপনি প্রতিটি শ্রেণীর জন্য সময় বদলানোর বিষয়টি উভয় পথেই চলেছে ... উদাহরণস্বরূপ যদি আপনি বর্তমান সময়কালীন মিলিসের পরিবর্তে ন্যানোটাইমকে উপহাস করেন তবে আপনাকে জাভা.ইটিল.কন্ট্রন্ট না ভাঙতে খুব যত্নবান হতে হবে। থাম্বের নিয়ম হিসাবে, যদি কোনও তৃতীয় পক্ষের লাইব্রেরি পরীক্ষাগুলিতে ব্যবহার করা শক্ত হয়, আপনার লাইব্রেরির ইনপুটগুলি উপহাস করা উচিত নয়: আপনার লাইব্রেরিটি নিজেই উপহাস করা উচিত।
ড্যান বেরিনেদি

1
আমরা এই কৌশলটি পরীক্ষার জন্য ব্যবহার করি যেখানে আমরা অন্য কোনও উপহাস করি না। এটি ইন্টিগ্রেশন টেস্ট এবং আমরা পুরো স্ট্যাকটি পরীক্ষা করি যখন এটি করা উচিত কিনা তা করা উচিত যখন বছরের মধ্যে প্রথম কোনও ক্রিয়াকলাপ ঘটে etc. ইত্যাদি n অর্থ সব। আমি জাভাটিকে সময় বদলকারী বৈশিষ্ট্যগুলির সাথে দেখতে দেখতে পছন্দ করছিলাম যেহেতু আমার আগে থেকে একাধিকবার এর প্রয়োজন ছিল এবং সিস্টেম টাইমের সাথে জগাখিচুড়ি কারণ এটি অত্যন্ত দুর্ভাগ্যজনক।
কুমারী 47

7

পাওয়ারমক দুর্দান্ত কাজ করে। এটি কেবল উপহাস করার জন্য ব্যবহার করেছে System.currentTimeMillis()


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

1
@ virgo47 না, আপনি এটি ভুল বুঝতে পেরেছেন। পাওয়ারমক কখনই "আপনার ক্লাসপথের প্রতিটি শ্রেণি পরীক্ষা করে না"; এটি কেবলমাত্র ক্লাসগুলি পরীক্ষা করবে যা আপনি বিশেষভাবে এটি পরীক্ষা করতে বলেছিলেন ( @PrepareForTestপরীক্ষার ক্লাসে টীকা দেওয়ার মাধ্যমে )।
রোগারিও

1
@ রোগিরিও - আমি ঠিক এটি বুঝতে পারি - আমি বলেছিলাম "আপনাকে এটি করতে হবে ..."। এটি হ'ল যদি আপনি System.currentTimeMillisআপনার ক্লাসপথের যে কোনও জায়গায় কল করতে (কোনও লিবিব) আপনার প্রতি ক্লাস চেক করতে হবে। এটাই আমি বোঝাতে চেয়েছিলাম, আর কিছু নয়। মুল বক্তব্যটি হ'ল আপনি কলারের পক্ষে সেই আচরণকে বিদ্রূপ করেছেন ("আপনি বিশেষভাবে বলুন")। এটি সাধারণ পরীক্ষার জন্য ঠিক আছে তবে পরীক্ষাগুলির জন্য নয় যেখানে আপনি যে পদ্ধতিটি কোথা থেকে কল করেন তা নিশ্চিত হতে পারবেন না (যেমন গ্রন্থাগারের সাথে জড়িত আরও জটিল উপাদান পরীক্ষা)। এর অর্থ এই নয় যে পাওয়ারমক মোটেও ভুল, এর অর্থ হ'ল আপনি এ জাতীয় পরীক্ষার জন্য এটি ব্যবহার করতে পারবেন না।
কুমারী 47

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

6

আপনি আপনার পরীক্ষার ক্ষেত্রে সেট করতে পারবেন এমন একটি পূর্বনির্ধারিত মান ফেরানোর জন্য সিস্টেম শ্রেণিটি বুনতে অ্যাসেকট-ওরিয়েন্টেড প্রোগ্রামিং (এওপি, উদাহরণস্বরূপ AspectJ) ব্যবহার করুন।

অথবা কলটি আপনার নিজের অন্য কোনও ইউটিলিটি ক্লাসে System.currentTimeMillis()বা ডাইরেক্ট করতে অ্যাপ্লিকেশন ক্লাসগুলি বুনুন new Date()

বুনন সিস্টেম ক্লাস (java.lang.* ) তবে কিছুটা বেশি কৌশলযুক্ত এবং আপনাকে আরটি.জারের জন্য অফলাইন বয়নটি সম্পাদন করতে হবে এবং আপনার পরীক্ষার জন্য আলাদা জেডিকে / আরটি.জার ব্যবহার করতে হবে।

একে বাইনারি বুনন বলা হয় এবং সিস্টেম ক্লাসগুলির বুনন সম্পাদন করার জন্য এবং এর সাথে কিছু সমস্যা নিরসনের জন্য বিশেষ সরঞ্জামও রয়েছে (যেমন ভিএম বুটস্ট্র্যাপিং কাজ নাও করতে পারে)


এটি অবশ্যই কাজ করে তবে একটি এওপি সরঞ্জামের চেয়ে উপহাসের সরঞ্জামটি করা আরও সহজ; পরের ধরণের সরঞ্জামটি প্রশ্নে উদ্দেশ্যটির জন্য খুব সাধারণ।
Rogério

3

সরাসরি ভিএম-তে সরাসরি এটি করার কোনও উপায় নেই তবে আপনি পরীক্ষার মেশিনে সিস্টেমের সময় নির্ধারণের জন্য সমস্ত কিছু করতে পারেন। এটি করার জন্য বেশিরভাগ (সমস্ত?) ওএসের কমান্ড লাইন কমান্ড রয়েছে।


উদাহরণস্বরূপ, উইন্ডোতে উইন্ডো dateএবং timeকমান্ডগুলি। লিনাক্স dateকমান্ড।
জেরেমি রেমন্ড

কেন এওপি বা যন্ত্রের সাহায্যে এটি করা সম্ভব হবে না (সেখানে এটি হয়ে গেছে)?
jarnbjo

3

জোডা সময় ব্যতীত, এবং পাওয়ারমক ছাড়াই ইজিমাকের সাথে একটি জাভা 8 ওয়েব অ্যাপ্লিকেশনটিতে JUnit পরীক্ষার উদ্দেশ্যে বর্তমান সিস্টেম সময়কে ওভাররাইড করার একটি কার্যকরী উপায়।

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

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

ধাপ 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;
  private int month = 2;
  private int day = 3;

  @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()


2

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

জেএমকিত ... কেবল সীমিত সংখ্যার জন্য কাজ করে সময়ের

পাওয়ারমক ও কো ... ক্লায়েন্টদের উপহাস করা দরকার সিস্টেম.কোর্নটাইমমিলিস () করা দরকার। আবার আক্রমণাত্মক বিকল্প।

এ থেকে আমি কেবল উল্লিখিত জাভাজেন্ট বা এওপ দেখতে পাচ্ছি পদ্ধতির পুরো সিস্টেমটিতে স্বচ্ছ হতে । কেউ কি এমনটি করেছে এবং এরকম সমাধানের দিকে ইঙ্গিত করতে পারে?

@ জার্নবজো: আপনি কিছু জাভাজেন্ট কোড দেখাতে পারেন?


3
অল্প অল্প সময়ের সাথে সীমাহীন সংখ্যক সময়ের জন্য jmockit সমাধান কাজ করছে: -ইনলাইন হ্যাক (সান এর হটস্পট এ): virgo47.wordpress.com/2012/06/22/ পরিবর্তন- সিস্টেম-সময়- ইন- জাভা সম্পূর্ণ হ্যান্ডি ক্লাস সিস্টেমটাইমশিফটার সরবরাহ করা হয় পদে. ক্লাসটি আপনার পরীক্ষাগুলিতে ব্যবহার করা যেতে পারে বা অন্য সময়ে আপনার অ্যাপ্লিকেশনটি (বা এমনকি পুরো অ্যাপসাইভার) চালানোর জন্য এটি খুব সহজেই আপনার আসল মূল শ্রেণীর আগে ব্যবহার করা যেতে পারে। অবশ্যই, এটি পরীক্ষার উদ্দেশ্যে মূলত উত্পাদন পরিবেশের জন্য নয়।
কুমারী 47

2

আপনি যদি লিনাক্স চালাচ্ছেন তবে আপনি লাইবফেকটাইমের মাস্টার শাখা ব্যবহার করতে পারেন বা পরীক্ষার সময় 4ce2835 কমিট করতে পারেন

আপনি আপনার জাভা অ্যাপ্লিকেশনটিকে যে সময়ের সাথে উপহাস করতে চান তার সাথে কেবল পরিবেশের পরিবর্তনশীল সেট করুন এবং এলডি-প্রিলোডিং ব্যবহার করে এটি চালান:

# bash
export FAKETIME="1985-10-26 01:21:00"
export DONT_FAKE_MONOTONIC=1
LD_PRELOAD=/usr/local/lib/faketime/libfaketimeMT.so.1 java -jar myapp.jar

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

আপনি যদি সিস্টেমড পরিচালিত পরিষেবার সময় পরিবর্তন করতে চান তবে কেবল আপনার ইউনিট ফাইলের ওভাররাইডগুলিতে নিম্নলিখিতগুলি যুক্ত করুন, যেমন ইলাস্টিক অনুসন্ধানের জন্য এটি হ'ল /etc/systemd/system/elasticsearch.service.d/override.conf:

[Service]
Environment="FAKETIME=2017-10-31 23:00:00"
Environment="DONT_FAKE_MONOTONIC=1"
Environment="LD_PRELOAD=/usr/local/lib/faketime/libfaketimeMT.so.1"

D systemctl ডেমন-পুনরায় লোড ব্যবহার করে সিস্টেমেড পুনরায় লোড করতে ভুলবেন না


-1

আপনি যদি System.currentTimeMillis()যুক্তিযুক্ত পদ্ধতিটি উপহাস করতে চান তবে আপনি anyLong()ম্যাচেরার ক্লাসটি একটি আর্গুমেন্ট হিসাবে পাস করতে পারেন ।

PS আমি উপরোক্ত কৌশলটি সফলভাবে আমার পরীক্ষার কেসটি সাফল্যের সাথে চালাতে সক্ষম হয়েছি এবং আমি আমার পরীক্ষার বিষয়ে আরও বিশদ জানাতে যা আমি পাওয়ারমক এবং মকিতো ফ্রেমওয়ার্কগুলি ব্যবহার করছি।

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