2017-09-16 56 views
10
Android Studio 3.0 Beta 5 
robolectric:3.3.1 

Tôi có trình giữ chế độ xem sau tải url hình ảnh bằng thư viện trượt. Tôi cố gắng để tìm thấy một cách để đơn vị kiểm tra này:Kiểm tra đơn vị Trượt: đảm bảo ImageView có hình ảnh chính xác

public class MovieActorsViewHolder extends RecyclerView.ViewHolder { 
     @BindView(R.id.civActorPicture) CircleImageView actorPicture; 
     @BindView(R.id.tvName) TextView name; 
     @BindView(R.id.tvCharacter) TextView character; 

     private Context context; 

     public MovieActorsViewHolder(View itemView) { 
      super(itemView); 
      ButterKnife.bind(this, itemView); 

      context = itemView.getContext(); 
     } 

     public void populateActor(Actor actor) { 
      Glide.with(context) 
        .load(actor.getPicturePath()) 
        .placeholder(R.drawable.people_placeholder) 
        .into(actorPicture); 

      name.setText(actor.getName()); 
      character.setText(actor.getCharacter()); 
     } 
    } 

Đây là bài kiểm tra đơn vị tôi đã làm, nhưng tôi không chắc chắn như thế nào tôi có thể kiểm tra đơn vị điểm ảnh. Tôi không chắc việc sử dụng Mockito để giả lập thư viện Glide có hiệu quả không?

@RunWith(RobolectricTestRunner.class) 
public class MovieActorsViewHolderTest { 
    private MovieActorsViewHolder movieActorsViewHolder; 

    @Before 
    public void setup() { 
     final Context context = ShadowApplication.getInstance().getApplicationContext(); 
     final View view = LayoutInflater.from(context).inflate(R.layout.movie_actors_item, new LinearLayout(context)); 

     movieActorsViewHolder = new MovieActorsViewHolder(view); 
    } 

    @Test 
    public void testShouldPopulateActorWithValidData() { 
     final Actor actor = getActor(); 
     movieActorsViewHolder.populateActor(actor); 

     /* test that the image view */ 
    final ShadowDrawable shadowDrawable = Shadows.shadowOf(movieActorsViewHolder.actorPicture.getDrawable()); 
    final Drawable drawable = Drawable.createFromPath(actor.getPicturePath()); 
    assertThat(drawable, is(shadowDrawable.getCreatedFromResId())); 

     assertThat(movieActorsViewHolder.name.getText(), is(actor.getName())); 
     assertThat(movieActorsViewHolder.character.getText(), is(actor.getCharacter())); 
    } 

    private Actor getActor() { 
    return new Actor(
      "https://image.tmdb.org/t/p/w92/dRLSoufWtc16F5fliK4ECIVs56p.jpg", 
      "Robert Danny Junior", 
      "Iron Man"); 
} 

}

Output:

Expected: is <[email protected]> 
    but: was <[email protected]> 
Expected :is <[email protected]> 

Actual :<[email protected]> 

Rất cám ơn cho bất cứ đề nghị.

+0

Ứng dụng có tải hình ảnh từ mạng hoặc từ tài nguyên không? –

Trả lời

18

nhưng tôi không chắc chắn làm thế nào tôi có thể đơn vị kiểm tra xem hình ảnh

Tôi nghĩ bạn đang đi sai hướng: bạn muốn kiểm tra xem Glide i s làm việc như mong đợi. Đó không phải là trách nhiệm của bạn với tư cách là khách hàng của thư viện đó. Glide có các thử nghiệm riêng của mình để xác minh nó hoạt động như mong đợi, bạn chỉ nên kiểm tra đơn vị logic mà bạn triển khai trong ứng dụng của mình.

Tuy nhiên, nếu bạn vẫn muốn làm điều gì đó tương tự, bạn phải giới thiệu một số sự tách biệt trong ViewHolder: một thành phần chịu trách nhiệm tải hình ảnh vào ImageView.

 

    public interface ImageLoader { 

     void load(Context context, 
        String path, 
        @DrawableRes int placeholder, 
        ImageView imageView); 
    } 
 

ai thực hiện được sau lớp:

 

    public class ImageLoaderImpl implements ImageLoader { 

     @Override 
     public void load(Context context, String path, int placeholder, ImageView imageView) { 
      Glide.with(context) 
        .load(path) 
        .placeholder(placeholder) 
        .into(imageView); 
     } 

    } 
 

Bây giờ ViewHolder của bạn sẽ trở thành một cái gì đó như thế này:

 

    class MovieActorsViewHolder extends RecyclerView.ViewHolder { 

     @BindView(R.id.picture) 
     ImageView imageView; 
     // other views 

     ImageLoader imageLoader; 

     MovieActorsViewHolder(View itemView, ImageLoader imageLoader) { 
      super(itemView); 
      ButterKnife.bind(this, itemView); 

      this.imageLoader = imageLoader; 
     } 

     void populateActor(Actor actor) { 
      imageLoader.load(itemView.getContext(), 
        actor.getPicturePath(), 
        R.drawable.people_placeholder, 
        imageView); 

      // other actions     
     } 

    } 
 

này sẽ cung cấp cho bạn sự linh hoạt để thử ImageLoader lớp.

Bây giờ để kiểm tra. Dưới đây là các thiết lập:

 

    @Before 
    public void setup() { 
     imageLoader = Mockito.mock(ImageLoader.class); 

     activity = Robolectric.setupActivity(MainActivity.class); 
     ViewGroup root = (ViewGroup) activity.findViewById(R.id.root); 

     View inflated = activity.getLayoutInflater().inflate(R.layout.item, root); 
     holder = new MovieActorsViewHolder(inflated, imageLoader); 
    } 
 

Và đây là phương pháp thử nghiệm:

 

    @Test 
    public void test() throws InterruptedException { 
     final String path = "https://image.tmdb.org/t/p/w92/dRLSoufWtc16F5fliK4ECIVs56p.jpg"; 
     final Actor actor = new Actor(path); 
     final Bitmap bitmap = Shadow.newInstanceOf(Bitmap.class); 
     final BitmapDrawable drawable = new BitmapDrawable(activity.getResources(), bitmap); 

     doAnswer(new Answer() { 
      @Override 
      public Object answer(InvocationOnMock invocation) throws Throwable { 
       holder.imageView.setImageDrawable(drawable); 
       return null; 
      } 
     }).when(imageLoader).load(activity, path, R.drawable.people_placeholder, holder.imageView); 

     holder.populateActor(actor); 

     assertEquals(holder.imageView.getDrawable(), drawable); 
    } 
 

này sẽ vượt qua. Nhưng hãy tự hỏi: bạn đã thử nghiệm cái gì với cái này? Thay vào đó, một thử nghiệm tốt hơn là đảm bảo rằng imageLoader.load(...) đã được gọi với các thông số chính xác, bỏ qua logic về cách Glide sẽ tải hình ảnh đó xuống ImageView.


Tôi đã không cố gắng thử nghiệm API Glide, nhưng chỉ để kiểm tra rằng hình ảnh đã được nạp thành công vào ImageView, hoặc có thể chỉ cần đảm bảo các lượn được gọi với các thông số chính xác.

Hai câu lệnh này về cơ bản giống nhau: nếu bạn xác minh rằng bạn ủy quyền công việc để Glide với thông số chính xác, hơn xác minh Glide sẽ tải hình ảnh chính xác.

Bây giờ, câu hỏi sẽ tóm tắt cách xác minh rằng bạn đang ủy nhiệm công việc để Glide với thông số chính xác?

Trong kịch bản nêu trên:

 

    holder.populateActor(actor); 

    verify(imageLoader).load(activity, path, R.drawable.people_placeholder, holder.imageView); 
 

này sẽ kiểm tra, cho dù imageLoader được truy vấn với những thông số.

chỉ cố gắng để tìm ra cách tốt nhất để đảm bảo xem hình ảnh có một hình ảnh

Những gì bạn muốn là tạo ra một khái niệm trừu tượng, mà sẽ điền vào các ImageView với một số giả Drawable, và trong phạm vi của bạn kiểm tra bạn sẽ kiểm tra xem ImageView đã thực sự được lấp đầy với điều đó có thể rút được hay không. Không chính xác điều này, bạn xác minh rằng phương thức trừu tượng của bạn đã được gọi (trong trường hợp nêu trên là ImageLoader#load())? Vì vậy, không cần phải kiểm tra rõ ràng liệu ImageView có được điền vào với số Drawable hay không, bởi vì nó chắc chắn sẽ, miễn là bạn cũng đã chế nhạo thành phần đó.

Tôi đoán điều này có nghĩa chế giễu Glide

Đừng phụ thuộc vào thực hiện, phụ thuộc vào sự trừu tượng. Điều gì xảy ra nếu sau này bạn quyết định chuyển từ Glide sang SomeAwesomeImageLoder? Bạn phải thay đổi mọi thứ trong nguồn của bạn cũng như kiểm tra.

Mặt khác, nếu bạn có một lớp chịu trách nhiệm tải hình ảnh, bạn chỉ đóng gói các lôgic tải trong lớp đó, do đó chỉ có lớp này sẽ cần thay đổi. Ngoài ra, điều này cho một đường may hoàn hảo để thực hiện kiểm tra đơn vị.

+1

Câu trả lời hay, tôi chỉ không thích thay đổi Glide fluent API thành phương thức giao tiếp với 4-5 tham số. Vì vậy, một câu trả lời tốt hơn một chút sẽ có giao diện điều khiển với API thông thạo giống như Glide API –

+0

@azizbekian, cảm ơn câu trả lời tuyệt vời. Thực ra, có lẽ tôi nên nói lại những gì tôi đang cố gắng đạt được. Tôi đã không cố gắng kiểm tra API Glide, chỉ cố gắng tìm cách tốt nhất để đảm bảo chế độ xem hình ảnh có hình ảnh hoặc đảm bảo trượt được gọi với thông số chính xác (tôi đoán điều này có nghĩa là chế nhạo Glide). Tôi hy vọng điều này rõ ràng hơn. Cảm ơn – ant2009

+0

@ ant2009, đã cập nhật. – azizbekian

2

Trong Robolectric, bạn có thể đặt số drawable được đặt thành imageview và xác nhận điều đó.

ShadowDrawable shadowDrawable = Shadows.shadowOf(imageView.getDrawable()); 
     assertEquals(expected, shadowDrawable.getCreatedFromResId()); 

Trong trường hợp của bạn, bạn có thể làm -

final Actor actor = getActor(); 
movieActorsViewHolder.populateActor(actor); 
ShadowDrawable shadowDrawable = Shadows.shadowOf(movieActorsViewHolder.actorPicture.getDrawable()); 
Drawable expected = Drawable.createFromPath(actor.getPicturePath()); 
assertEquals(expected, shadowDrawable.getCreatedFromResId()); 

Lưu ý: Đây được kiểm tra và làm việc tại Robolectric 3.3.1

+0

@ ant2009 Liệu nó không giải quyết được vấn đề của bạn? –

+0

có vấn đề tôi nhận được sau đây Dự kiến: là <2130837650> Thực tế: <[email protected]> Có vẻ như tôi chỉ so sánh thực tế có thể vẽ không phải là id tài nguyên. Dường như tôi đang so sánh một drawable với một int. – ant2009

Các vấn đề liên quan