ant*_*009 14 testing android unit-testing robolectric android-glide
Android Studio 3.0 Beta 5
robolectric:3.3.1
Run Code Online (Sandbox Code Playgroud)
我有一个以下视图持有者使用滑动库加载图像URL.我试图找到一种单元测试的方法:
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());
}
}
Run Code Online (Sandbox Code Playgroud)
这是我所做的单元测试,但我不知道如何对图像视图进行单元测试.我不确定使用Mockito模拟Glide库会起作用吗?
@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");
}
Run Code Online (Sandbox Code Playgroud)
}
输出:
Expected: is <org.robolectric.shadows.ShadowBitmapDrawable@ffffffe0>
but: was <android.graphics.drawable.BitmapDrawable@ffffffe0>
Expected :is <org.robolectric.shadows.ShadowBitmapDrawable@ffffffe0>
Actual :<android.graphics.drawable.BitmapDrawable@ffffffe0>
Run Code Online (Sandbox Code Playgroud)
非常感谢任何建议.
azi*_*ian 21
但我不知道如何对图像视图进行单元测试
我认为你的方法是错误的:你想测试Glide是否按预期工作.作为该图书馆的客户,这不是您的责任.Glide有自己的测试,可以验证它是否按预期工作,您应该只对您在应用程序中实现的逻辑进行单元测试.
然而,如果你仍然想要做类似的事情,那么你必须在你ViewHolder
的内容中引入一些分离:一个负责将图像加载到的组件ImageView
.
public interface ImageLoader {
void load(Context context,
String path,
@DrawableRes int placeholder,
ImageView imageView);
}
以下是谁的实施:
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);
}
}
现在你的ViewHolder
意志会变成这样:
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
}
}
这将为您提供模拟ImageLoader
课程的灵活性.
现在来测试一下.这是设置:
@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);
}
这是测试方法:
@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);
}
这将通过.但问问自己:你用这个测试了什么?相反,更好的测试是确保imageLoader.load(...)
使用正确的参数调用,忽略Glide将如何下载该图像的逻辑ImageView
.
我没有尝试测试Glide API,只是为了测试图像是否成功加载到imageview中,或者只是确保使用正确的参数调用滑动.
这两个语句基本相同:如果您验证是否使用正确的参数将作业委托给Glide,那么它会验证Glide是否会正确加载图像.
现在,问题归结为如何验证您是否使用正确的参数将作业委托给Glide?
在上面提到的场景中:
holder.populateActor(actor);
verify(imageLoader).load(activity, path, R.drawable.people_placeholder, holder.imageView);
这将检查是否imageLoader
使用这些参数查询.
只是想找到确保图像视图有图像的最佳方法
你想要的是创建一个抽象,ImageView
用一些模拟来填充Drawable
,在你的测试中你会检查是否ImageView
实际上已经填充了那个drawable.这是不是完全相同,你验证你的抽象方法被调用(在上面提到的情况下ImageLoader#load()
)?所以,没有必要明确检查是否ImageView
填充了Drawable
,因为它肯定会,只要你也模拟了该组件.
我想这意味着嘲笑Glide
不依赖于实现,依赖于抽象.如果你以后决定从移动Glide
到SomeAwesomeImageLoder
?您必须更改源和测试中的所有内容.
另一方面,如果您有一个负责图像加载的类,则只将加载逻辑封装在该类中,因此只需要更改此类.此外,这提供了完美的接缝来执行单元测试.
归档时间: |
|
查看次数: |
3056 次 |
最近记录: |