Tôi có thể sử dụng khẳng định trên thiết bị Android không?


88

Tôi muốn sử dụng từ khóa Assert trong các ứng dụng Android của mình để phá hủy ứng dụng của mình trong một số trường hợp trên trình giả lập hoặc thiết bị của tôi trong quá trình thử nghiệm. Điều này có khả thi không?

Có vẻ như trình giả lập chỉ phớt lờ những khẳng định của tôi.


2
Đối với ART, thay vì Dalvik, hãy xem stackoverflow.com/questions/35997703/…
fadden,

Lưu ý rằng câu trả lời được chấp nhận là khá sai lầm.
giảm hoạt động vào

Câu trả lời:


-7

API cung cấp JUnit Assert .

Bạn có thể làm

import static junit.framework.Assert.*;

bây giờ bạn có thể sử dụng tất cả các chức năng như khẳng định, khẳng định, khẳng định, khẳng địnhNull được cung cấp trong khuôn khổ junit.

Hãy cẩn thận không nhập khung công tác Junit4 thông qua eclipse, đó sẽ là gói org.junit. Bạn phải sử dụng gói junit.framework để làm cho nó hoạt động trên thiết bị Android hoặc trình giả lập.


51
Vâng, OP đã yêu cầu “từ khóa khẳng định” - không giống như junit.framework.Assert có thể được tối ưu hóa bởi JIT. Và vì lý do này mà tôi đến đây. Hy vọng một số câu trả lời khác sẽ hữu ích hơn.
Martin

27
Tôi ghét phải thô lỗ nhưng đây không phải là câu trả lời được chấp nhận vì nó không trả lời câu hỏi (Tôi đồng ý với bình luận của @Martin). Câu trả lời khác giải thích làm thế nào để thực hiện các chức năng từ khóa khẳng định đúng, ví dụ như chạy "adb shell setprop Debug.Assert 1"
jfritz42

3
Bị phản đối vì OP hỏi về từ khóa khẳng định. @scorpiodawg đã phác thảo quy trình bên dưới: stackoverflow.com/a/5563637/484261

Câu trả lời của scorpiodawg chỉ đến một năm sau đó, vì vậy tôi đoán câu trả lời này chỉ được chấp nhận vì OP, vì một số lý do, cảm thấy có nghĩa vụ đánh dấu một câu trả lời là được chấp nhận. Thái độ này làm cho một số lượng lớn các câu trả lời trên SO hoặc không đầy đủ hoặc hoàn toàn khủng khiếp.
async

145

Xem tài liệu Điều khiển máy ảo được nhúng (HTML thô từ cây nguồn hoặc bản sao được định dạng đẹp mắt ).

Về cơ bản, Dalvik VM được thiết lập để bỏ qua kiểm tra xác nhận theo mặc định, mặc dù mã byte .dex bao gồm mã để thực hiện kiểm tra. Kiểm tra xác nhận được bật theo một trong hai cách:

(1) bằng cách đặt thuộc tính hệ thống "debug.assert" qua:

adb shell setprop debug.assert 1

mà tôi đã xác minh hoạt động như dự định miễn là bạn cài đặt lại ứng dụng của mình sau khi thực hiện việc này hoặc

(2) bằng cách gửi đối số dòng lệnh "--enable-khẳng định" đến máy ảo dalvik, đây có thể không phải là điều mà các nhà phát triển ứng dụng có thể làm được (ai đó sẽ sửa cho tôi nếu tôi sai ở đây).

Về cơ bản, có một cờ có thể được đặt trên toàn cục, ở cấp gói hoặc ở cấp lớp cho phép xác nhận ở cấp tương ứng đó. Cờ bị tắt theo mặc định, do đó các kiểm tra xác nhận bị bỏ qua.

Tôi đã viết mã sau trong Hoạt động mẫu của mình:


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;
  }
}

Đối với mã này, mã byte dalvik được tạo là (dành cho 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

Lưu ý cách phương thức khởi tạo tĩnh gọi phương thức wishAssertionStatus trên đối tượng Lớp và đặt biến toàn lớp $ khẳng địnhDisabled; cũng lưu ý rằng trong onCreate (), tất cả mã để ném java.lang.AssertionError đều được biên dịch, nhưng việc thực thi nó phụ thuộc vào giá trị của $ confirmtionsDisabled được đặt cho đối tượng Class trong hàm tạo tĩnh.

Có vẻ như lớp Assert của JUnit là thứ được sử dụng chủ yếu, vì vậy, có thể là một lựa chọn an toàn để sử dụng nó. Tính linh hoạt của từ khóa khẳng định là khả năng bật xác nhận tại thời điểm phát triển và tắt chúng để vận chuyển các bit và thay vào đó là thất bại một cách duyên dáng.

Hi vọng điêu nay co ich.


Có vẻ như Google đã xóa nguồn có thể duyệt (tôi đã thấy các tham chiếu đến nguồn này trong câu trả lời cho các câu hỏi khác tại đây). Đặt cược tốt nhất của bạn là lấy nguồn hoặc cố gắng tra cứu điều này trong một công cụ tìm kiếm. Tìm kiếm "dalvik / nhúng-vm-control.html". Đây là một nơi có nó: assemblybla.com/code/android-gb-for-sharp-is01/git/nodes/dalvik/… . Hi vọng điêu nay co ich.
scorpiodawg

Rất hữu ích, cảm ơn bạn. Tuy nhiên, tôi bối rối bởi sự phân biệt được thực hiện trong đoạn văn thứ hai đến cuối cùng. Chúng ta đang thảo luận về hai loại xác nhận: Loại thứ nhất là các phương thức của gói JUnit Assert như khẳng địnhNotNull () và loại thứ hai là từ khóa 'khẳng định' của ngôn ngữ Java. Câu trả lời của bạn có áp dụng cho cả hai không? Ví dụ: nếu tôi import static junit.framework.Assert.*và sau đó tôi sử dụng một trong các phương thức của nó, chẳng hạn như assertNotNull("It's null!", someObject);xác nhận này có bị tắt trong các bit vận chuyển không?
Jeffro

1
Xin chào Jeffro, tôi không tin như vậy - junit.framework.Assert chỉ đơn giản là một lớp ném ra một ngoại lệ khi điều kiện đầu vào được phát hiện là sai. Mặt khác, từ khóa khẳng định được tích hợp sẵn trong ngôn ngữ. Hi vọng điêu nay co ich.
scorpiodawg

3
Có cách nào để thực hiện adb shell setprop debug.assert 1trong Eclipse không?
Pacerier

1
Việc xác nhận cũng có thể được thực hiện từ một thiết bị đầu cuối đang chạy trên thiết bị nếu bạn đã root. Đầu tiên su, sau đó setprop debug.assert 1. Lưu ý rằng mã mà bạn hiển thị đã được tháo rời sẽ ở trong bản phát hành ( stackoverflow.com/a/5590378/506073 ). Tôi không tin rằng trình biên dịch javac có thể được yêu cầu không phát ra xác nhận vì vậy chúng cần được loại bỏ bằng cách nào đó. Một giải pháp đơn giản cho điều đó là bọc từ khóa khẳng định trong chức năng của riêng bạn mà proguard có thể tách ra cho bạn.
ahcox

10

Khi các xác nhận được bật, asserttừ khóa chỉ cần ném một AssertionErrorkhi biểu thức boolean là false.

Vì vậy, IMO, giải pháp thay thế tốt nhất, đặc biệt. nếu bạn không thích phụ thuộc vào junit, hãy ném một AssertionErrorcách rõ ràng như hình dưới đây:

assert x == 0 : "x = " + x;

Một thay thế cho tuyên bố trên là:

Utils._assert(x == 0, "x = " + x);

Trong đó phương thức được định nghĩa là:

public static void _assert(boolean condition, String message) {
    if (!condition) {
        throw new AssertionError(message);
    }
}

Các tài liệu Oracle java khuyên bạn nên ném AssertionErrormột tệp thay thế có thể chấp nhận được.

Tôi đoán bạn có thể định cấu hình Proguard để loại bỏ các lệnh gọi này cho mã sản xuất.


Nhưng làm cách nào để kích hoạt xác nhận? Trên Android Studio?
SMBiggs

8

Trong "Android in Practice", bạn nên sử dụng:

$adb shell setprop dalvik.vm.enableassertions all

nếu cài đặt này không được duy trì trên điện thoại của bạn thì bạn có thể tạo tệp /data/local.prop với các thuộc tính như:

dalvik.vm.enableassertions=all

Theo stackoverflow.com/a/18556839/2004714 , bạn cũng có thể cần đảm bảo rằng tệp được đặt ở chế độ chỉ đọc ( chmod 644).
Paulo

5

Tôi thật buồn khi những khẳng định của tôi không hoạt động, cho đến khi tôi kiểm tra vấn đề trên google ... Tôi đã từ bỏ những khẳng định đơn giản và sẽ sử dụng các phương pháp xác nhận junits.

Vì mục đích thuận tiện, tôi đang sử dụng:

nhập static junit.framework.Assert. *;

Do nhập tĩnh, sau này tôi có thể viết:

khẳng địnhTrue (...); thay vì Assert.assertTrue (...);


4

Nếu bạn lo lắng về mã vận chuyển với các xác nhận JUnit trong (hoặc bất kỳ đường dẫn lớp nào khác), bạn có thể sử dụng tùy chọn cấu hình ProGuard 'giả định', tùy chọn này sẽ loại bỏ một đường dẫn lớp với giả định rằng việc xóa nó không ảnh hưởng gì đến mã .

Ví dụ.

-assumenosideeffects junit.framework.Assert {
*;
}

Tôi có một thư viện gỡ lỗi chung mà tôi đã đưa tất cả các phương pháp thử nghiệm của mình vào và sau đó sử dụng tùy chọn này để loại bỏ nó khỏi các ứng dụng đã phát hành của tôi.

Điều này cũng loại bỏ vấn đề khó phát hiện về các chuỗi được thao tác không bao giờ được sử dụng trong mã phát hành. Ví dụ: nếu bạn viết một phương thức ghi nhật ký gỡ lỗi và trong phương thức đó, bạn kiểm tra chế độ gỡ lỗi trước khi ghi vào chuỗi, bạn vẫn đang xây dựng chuỗi, cấp phát bộ nhớ, gọi phương thức, nhưng sau đó chọn không làm gì cả. Việc tách lớp ra sau đó loại bỏ hoàn toàn các lời gọi, có nghĩa là miễn là chuỗi của bạn được xây dựng bên trong lời gọi phương thức, nó cũng sẽ biến mất.

Tuy nhiên, hãy đảm bảo rằng bạn thực sự an toàn nếu chỉ cắt bỏ các đường kẻ vì nó được thực hiện mà không cần kiểm tra trên phần của ProGuard. Loại bỏ bất kỳ phương thức trả về void sẽ không sao, tuy nhiên nếu bạn đang lấy bất kỳ giá trị trả về nào từ bất kỳ giá trị nào bạn đang xóa, hãy đảm bảo rằng bạn không sử dụng chúng cho logic hoạt động thực tế.


1
Tôi nghĩ rằng cú pháp thích hợp sẽ là:-assumenosideeffects class junit.framework.Assert { *; }
Pooks

Câu trả lời khó hiểu. Lệnh được đề cập gây ra lỗi proguard. Lệnh được Pooks sửa vẫn không xóa xác nhận khỏi tệp dex nhị phân.
Pointer Null

Tôi gặp vấn đề tương tự @PointerNull. khẳng định sẽ không bị xóa.
Mahdi

3

Bạn có thể sử dụng các xác nhận, nhưng phải mất một số công việc để sử dụng chúng một cách đáng tin cậy. Thuộc tính hệ thống debug.assertlà không đáng tin cậy; xem các số báo 175697 , 65183 , 3678617324 .

Một phương pháp là dịch từng assertcâu lệnh thành một thứ mà bất kỳ thời gian chạy nào cũng có thể xử lý. Thực hiện việc này với bộ tiền xử lý nguồn phía trước trình biên dịch Java. Ví dụ: lấy câu lệnh sau:

assert x == 0: "Failure message";

Đối với bản dựng gỡ lỗi, bộ xử lý trước của bạn sẽ dịch phần trên thành một ifcâu lệnh:

{ if( !(x == 0) ) throw new AssertionError( "Failure message" ); }

Đối với một bản dựng sản xuất, với một câu lệnh trống:

;

Lưu ý rằng điều này sẽ kiểm soát các xác nhận tại thời điểm xây dựng, trái ngược với thời gian chạy (cách làm thông thường).

Tôi không thể tìm thấy bộ xử lý tiền chế tạo sẵn nào, vì vậy tôi đã viết kịch bản cho một bộ xử lý . Xem phần xử lý các xác nhận. Giấy phép để sao chép là ở đây .


1

Để thêm vào câu trả lời của Zulaxia về việc loại bỏ Junit - Proguard đã là một phần của Android SDK / Eclipse và trang sau sẽ cho bạn biết cách bật nó.

http://developer.android.com/guide/developing/tools/proguard.html

Ngoài ra, cấu hình ở trên sẽ không hoạt động với cấu hình proguard mặc định mới nhất vì nó sử dụng cờ -dontoptimize phải được loại bỏ và một số tối ưu hóa được bật.


0

Sử dụng từ khóa khẳng định Java tiêu chuẩn , ví dụ:

assert a==b;

Để điều này hoạt động, bạn phải thêm một dòng vào /system/build.prop và khởi động lại điện thoại:

debug.assert=1

Điều này sẽ hoạt động trên điện thoại đã root. Sử dụng một số trình quản lý tệp có khả năng chỉnh sửa build.prop (ví dụ: X-plore).

Điểm cộng: hầu hết (tất cả?) Điện thoại Android đều bị vô hiệu hóa tính năng xác nhận. Ngay cả khi mã của bạn vô tình xác nhận là sai, ứng dụng sẽ không làm gián đoạn hoặc gặp sự cố. Tuy nhiên, trên thiết bị phát triển của bạn, bạn sẽ nhận được ngoại lệ xác nhận.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.