ฉันต้องการใช้คีย์เวิร์ดAssertในแอพ Android ของฉันเพื่อทำลายแอพของฉันในบางกรณีบนโปรแกรมจำลองหรืออุปกรณ์ของฉันในระหว่างการทดสอบ เป็นไปได้หรือไม่
ดูเหมือนว่าโปรแกรมจำลองจะไม่สนใจคำยืนยันของฉัน
ฉันต้องการใช้คีย์เวิร์ดAssertในแอพ Android ของฉันเพื่อทำลายแอพของฉันในบางกรณีบนโปรแกรมจำลองหรืออุปกรณ์ของฉันในระหว่างการทดสอบ เป็นไปได้หรือไม่
ดูเหมือนว่าโปรแกรมจำลองจะไม่สนใจคำยืนยันของฉัน
คำตอบ:
API ที่ให้JUnit ยืนยัน
คุณทำได้
import static junit.framework.Assert.*;
ตอนนี้คุณสามารถใช้ฟังก์ชันทั้งหมดเช่น assertTrue, assertEquals, assertNull ที่มีให้ในกรอบงาน junit
ระวังอย่าอิมพอร์ตเฟรมเวิร์ก Junit4 ผ่าน eclipse ซึ่งจะเป็นแพ็กเกจ org.junit คุณต้องใช้แพ็คเกจ junit.framework เพื่อให้มันทำงานบนอุปกรณ์ Android หรือโปรแกรมจำลอง
ดูเอกสาร Embedded VM Control (HTML ดิบจากแผนผังต้นทางหรือสำเนาที่มีรูปแบบสวยงาม )
โดยทั่วไป Dalvik VM ถูกตั้งค่าให้ละเว้นการตรวจสอบการยืนยันตามค่าเริ่มต้นแม้ว่ารหัสไบต์. dex จะมีรหัสสำหรับทำการตรวจสอบก็ตาม การตรวจสอบการยืนยันเปิดอยู่ด้วยหนึ่งในสองวิธี:
(1) โดยตั้งค่าคุณสมบัติระบบ "debug.assert" ผ่าน:
adb shell setprop debug.assert 1
ซึ่งฉันตรวจสอบแล้วว่าใช้งานได้ตามที่ตั้งใจไว้ตราบเท่าที่คุณติดตั้งแอปของคุณใหม่หลังจากทำสิ่งนี้หรือ
(2) โดยการส่งอาร์กิวเมนต์บรรทัดคำสั่ง "--enable-assert" ไปยัง dalvik VM ซึ่งอาจไม่ใช่สิ่งที่นักพัฒนาแอปสามารถทำได้ (มีใครแก้ไขฉันได้ถ้าฉันผิดที่นี่)
โดยทั่วไปมีแฟล็กที่สามารถตั้งค่าได้ทั้งแบบทั่วโลกในระดับแพ็กเกจหรือในระดับคลาสซึ่งเปิดใช้งานการยืนยันในระดับนั้น ๆ แฟล็กถูกปิดโดยค่าเริ่มต้นซึ่งเป็นผลมาจากการที่การตรวจสอบการยืนยันถูกข้ามไป
ฉันเขียนโค้ดต่อไปนี้ในกิจกรรมตัวอย่างของฉัน:
public class AssertActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
int x = 2 + 3;
assert x == 4;
}
}
สำหรับรหัสนี้รหัส dalvik byte ที่สร้างขึ้นคือ (สำหรับ Android 2.3.3):
// Static constructor for the class
000318: |[000318] com.example.asserttest.AssertActivity.:()V
000328: 1c00 0300 |0000: const-class v0, Lcom/example/asserttest/AssertActivity; // class@0003
00032c: 6e10 0c00 0000 |0002: invoke-virtual {v0}, Ljava/lang/Class;.desiredAssertionStatus:()Z // method@000c
000332: 0a00 |0005: move-result v0
000334: 3900 0600 |0006: if-nez v0, 000c // +0006
000338: 1210 |0008: const/4 v0, #int 1 // #1
00033a: 6a00 0000 |0009: sput-boolean v0, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000
00033e: 0e00 |000b: return-void
000340: 1200 |000c: const/4 v0, #int 0 // #0
000342: 28fc |000d: goto 0009 // -0004
:
:
// onCreate()
00035c: |[00035c] com.example.asserttest.AssertActivity.onCreate:(Landroid/os/Bundle;)V
00036c: 6f20 0100 3200 |0000: invoke-super {v2, v3}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V // method@0001
000372: 1501 037f |0003: const/high16 v1, #int 2130903040 // #7f03
000376: 6e20 0500 1200 |0005: invoke-virtual {v2, v1}, Lcom/example/asserttest/AssertActivity;.setContentView:(I)V // method@0005
00037c: 1250 |0008: const/4 v0, #int 5 // #5
00037e: 6301 0000 |0009: sget-boolean v1, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000
000382: 3901 0b00 |000b: if-nez v1, 0016 // +000b
000386: 1251 |000d: const/4 v1, #int 5 // #5
000388: 3210 0800 |000e: if-eq v0, v1, 0016 // +0008
00038c: 2201 0c00 |0010: new-instance v1, Ljava/lang/AssertionError; // class@000c
000390: 7010 0b00 0100 |0012: invoke-direct {v1}, Ljava/lang/AssertionError;.:()V // method@000b
000396: 2701 |0015: throw v1
000398: 0e00 |0016: return-void
สังเกตว่าคอนสตรัคเตอร์แบบคงที่เรียกใช้เมธอด neededAssertionStatus บนวัตถุคลาสและตั้งค่าตัวแปร $ assertionsDisabled โปรดสังเกตด้วยว่าใน onCreate () โค้ดทั้งหมดที่จะโยน java.lang.AssertionError จะถูกคอมไพล์ แต่การดำเนินการนั้นขึ้นอยู่กับค่าของ $ assertionsDisabled ซึ่งถูกตั้งค่าสำหรับอ็อบเจ็กต์ Class ในตัวสร้างแบบคงที่
ดูเหมือนว่าคลาส Assert ของ JUnit เป็นสิ่งที่ใช้เป็นส่วนใหญ่ดังนั้นจึงน่าจะเป็นการเดิมพันที่ปลอดภัยที่จะใช้สิ่งนั้น ความยืดหยุ่นของคีย์เวิร์ดที่ยืนยันคือความสามารถในการเปิดการยืนยันในช่วงเวลาการพัฒนาและปิดคีย์เวิร์ดสำหรับการจัดส่งบิตและล้มเหลวอย่างสง่างาม
หวังว่านี่จะช่วยได้
import static junit.framework.Assert.*
แล้วใช้วิธีใดวิธีหนึ่งเช่นassertNotNull("It's null!", someObject);
การยืนยันนี้ถูกปิดในการจัดส่งบิตหรือไม่
adb shell setprop debug.assert 1
ใน Eclipse หรือไม่?
su
setprop debug.assert 1
โปรดทราบว่ารหัสที่คุณแสดงการแยกชิ้นส่วนจะยังคงอยู่ในรุ่นรุ่น ( stackoverflow.com/a/5590378/506073 ) ฉันไม่เชื่อว่าคอมไพเลอร์ javac สามารถบอกได้ว่าจะไม่ปล่อยคำยืนยันดังนั้นพวกเขาจึงจำเป็นต้องถูกถอดออก วิธีแก้ปัญหาง่ายๆคือการรวมคำหลักที่ยืนยันในฟังก์ชันของคุณเองที่ proguard สามารถตัดให้คุณ
เมื่อยืนยันจะเปิดใช้งานassert
คำหลักเพียงแค่พ่นเมื่อนิพจน์บูลีนคือAssertionError
false
ดังนั้น IMO ซึ่งเป็นทางเลือกที่ดีที่สุดโดยเฉพาะ หากคุณไม่ชอบที่จะพึ่งพาจูนิทก็คือการโยนAssertionError
อย่างชัดเจนดังที่แสดงด้านล่าง:
assert x == 0 : "x = " + x;
อีกทางเลือกหนึ่งสำหรับข้อความข้างต้นคือ:
Utils._assert(x == 0, "x = " + x);
โดยวิธีการกำหนดเป็น:
public static void _assert(boolean condition, String message) {
if (!condition) {
throw new AssertionError(message);
}
}
Oracle java docs แนะนำให้โยนAssertionError
เป็นทางเลือกที่ยอมรับได้
ฉันเดาว่าคุณสามารถกำหนดค่า Proguard เพื่อตัดสายเหล่านี้ออกสำหรับรหัสการผลิต
ใน "Android in Practice" แนะนำให้ใช้:
$adb shell setprop dalvik.vm.enableassertions all
หากการตั้งค่านี้ไม่คงอยู่ในโทรศัพท์ของคุณคุณสามารถสร้างไฟล์ /data/local.prop ด้วยคุณสมบัติเช่น:
dalvik.vm.enableassertions=all
chmod 644
)
มันทำให้ฉันรู้สึกแย่มากที่การยืนยันของฉันไม่ได้ผลจนกว่าฉันจะตรวจสอบปัญหาใน google ... ฉันยอมแพ้กับการยืนยันง่ายๆและจะใช้วิธีการยืนยันแบบ Junits
เพื่อความสะดวกฉันใช้:
นำเข้า junit.framework.Assert แบบคงที่ *;
เนื่องจากการนำเข้าแบบคงที่ฉันสามารถเขียนได้ในภายหลัง:
assertTrue (... ); แทน Assert.assertTrue (... );
หากคุณกังวลเกี่ยวกับรหัสการจัดส่งที่มีการยืนยัน JUnit ใน (หรือพา ธ คลาสอื่น ๆ ) คุณสามารถใช้ตัวเลือกการกำหนดค่า ProGuard 'สมมติฐานผลกระทบ' ซึ่งจะตัดเส้นทางของคลาสออกโดยสมมติว่าการลบออกจะไม่ทำอะไรกับโค้ด .
เช่น.
-assumenosideeffects junit.framework.Assert {
*;
}
ฉันมีไลบรารีดีบักทั่วไปที่ฉันใส่วิธีการทดสอบทั้งหมดแล้วใช้ตัวเลือกนี้เพื่อดึงมันออกจากแอพที่ออก
นอกจากนี้ยังขจัดปัญหาที่ยากต่อการสังเกตเห็นของสตริงที่ถูกจัดการที่ไม่เคยใช้ในรหัสรุ่น ตัวอย่างเช่นถ้าคุณเขียนวิธีการบันทึกการดีบักและในวิธีนั้นคุณตรวจสอบโหมดดีบักก่อนที่จะบันทึกสตริงคุณยังคงสร้างสตริงจัดสรรหน่วยความจำเรียกใช้เมธอด แต่จากนั้นเลือกที่จะไม่ทำอะไรเลย การถอดคลาสออกจากนั้นจะลบการโทรออกทั้งหมดหมายความว่าตราบใดที่สตริงของคุณถูกสร้างขึ้นภายในการเรียกเมธอดมันก็จะหายไปเช่นกัน
ตรวจสอบให้แน่ใจว่ามีความปลอดภัยอย่างแท้จริงในการตัดเส้นออกอย่างไรก็ตามเนื่องจากไม่มีการตรวจสอบในส่วนของ ProGuard การลบวิธีการคืนค่าที่เป็นโมฆะจะใช้ได้ดีอย่างไรก็ตามหากคุณใช้ค่าส่งคืนใด ๆ จากสิ่งที่คุณกำลังลบตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้มันสำหรับตรรกะในการปฏิบัติงานจริง
-assumenosideeffects class junit.framework.Assert { *; }
คุณสามารถใช้การยืนยันได้ แต่ต้องใช้เวลาพอสมควรในการใช้อย่างน่าเชื่อถือ คุณสมบัติของระบบdebug.assert
ไม่น่าเชื่อถือ เห็นปัญหา175697 , 65183 , 36786และ17324
วิธีหนึ่งคือการแปลแต่ละassert
คำสั่งเป็นสิ่งที่รันไทม์สามารถจัดการได้ ดำเนินการนี้กับพรีโปรเซสเซอร์ซอร์สด้านหน้าคอมไพเลอร์ Java ตัวอย่างเช่นใช้คำสั่งนี้:
assert x == 0: "Failure message";
สำหรับบิวด์ดีบักตัวประมวลผลก่อนของคุณจะแปลข้างต้นเป็นif
คำสั่ง:
{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }
สำหรับบิลด์การผลิตไปยังคำสั่งว่าง:
;
โปรดทราบว่าสิ่งนี้จะควบคุมการยืนยันในเวลาสร้างซึ่งต่างจากเวลาทำงาน (การปฏิบัติตามปกติ)
ฉันไม่พบตัวประมวลผลล่วงหน้าสำเร็จรูปดังนั้นฉันจึงเขียนสคริปต์ขึ้นมา ดูส่วนที่เกี่ยวข้องกับการยืนยัน อนุญาตให้คัดลอกที่นี่
หากต้องการเพิ่มคำตอบของ Zulaxia เกี่ยวกับการแยก Junit ออก - Proguard เป็นส่วนหนึ่งของ Android SDK / Eclipse อยู่แล้วและหน้าต่อไปนี้จะบอกวิธีเปิดใช้งาน
http://developer.android.com/guide/developing/tools/proguard.html
นอกจากนี้ข้างต้นจะใช้ไม่ได้กับการกำหนดค่า proguard เริ่มต้นล่าสุดเนื่องจากใช้แฟล็ก -dontoptimize ซึ่งจะต้องถูกนำออกและการเพิ่มประสิทธิภาพบางอย่างเปิดอยู่
ใช้คีย์เวิร์ดJava assertมาตรฐานตัวอย่างเช่น:
assert a==b;
เพื่อให้ได้ผลคุณต้องเพิ่มหนึ่งบรรทัดใน /system/build.prop และรีบูตโทรศัพท์:
debug.assert=1
สิ่งนี้จะใช้ได้กับโทรศัพท์ที่รูท ใช้ตัวจัดการไฟล์บางตัวที่สามารถแก้ไข build.prop (เช่น X-plore)
ข้อดี: โทรศัพท์ Android ส่วนใหญ่ (ทั้งหมด?) มาพร้อมกับปิดใช้งานการยืนยัน แม้ว่ารหัสของคุณจะยืนยันว่าเป็นเท็จโดยไม่ตั้งใจ แต่แอปจะไม่ขัดจังหวะหรือขัดข้อง อย่างไรก็ตามบนอุปกรณ์การพัฒนาของคุณคุณจะได้รับข้อยกเว้นในการยืนยัน