if not view_id:
view_id = self.env.ref('appartment.appartment_view_form').id
result = super(Appartments, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
doc = etree.XML(result['arch'])
node = doc.xpath("//field[@name='appartmentrooms_id']/tree/field[@name='partner_ids']")
print'node',node //Prints empty list
我有一个以下视图持有者,它使用滑动库加载图像URL。我正试图找到一种单元测试的方法:
Android Studio 3.0 Beta 5
robolectric:3.3.1
这是我所做的单元测试,但我不知道如何对图像视图进行单元测试。我不确定使用Mockito模拟Glide库会起作用吗?
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());
}
}
}
输出:
@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");
}
非常感谢任何建议。
答案 0 :(得分: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? p>
在上述场景中:
holder.populateActor(actor);
verify(imageLoader).load(activity, path, R.drawable.people_placeholder, holder.imageView);
这将检查是否使用这些参数查询imageLoader
。
只是想找到确保图片视图有图像的最佳方法
你想要的是创建一个抽象,用一些模拟ImageView
来填充Drawable
,在你的测试中你会检查ImageView
是否真的被填充了那个可画的。这是完全相同的,你验证你的抽象方法被调用(在上面提到的案例中ImageLoader#load()
)?因此,没有必要明确检查ImageView
是否已填入Drawable
,因为只要您同时嘲笑该组件,它也一定会被填充。
我想这意味着嘲笑Glide
不依赖于实现,依赖于抽象。如果您以后决定从Glide
转移到SomeAwesomeImageLoder
怎么办?您必须更改源和测试中的所有内容。
另一方面,如果您有一个负责图像加载的类,那么您只需将加载逻辑封装在该类中,因此只需要更改此类。此外,这为进行单元测试提供了完美的接缝。
答案 1 :(得分:2)
在Robolectric
中,您可以将drawable
设置为imageview
并对其进行断言。
ShadowDrawable shadowDrawable = Shadows.shadowOf(imageView.getDrawable());
assertEquals(expected, shadowDrawable.getCreatedFromResId());
在你的情况下,你可以做 -
final Actor actor = getActor();
movieActorsViewHolder.populateActor(actor);
ShadowDrawable shadowDrawable = Shadows.shadowOf(movieActorsViewHolder.actorPicture.getDrawable());
Drawable expected = Drawable.createFromPath(actor.getPicturePath());
assertEquals(expected, shadowDrawable.getCreatedFromResId());
注意:这已经过测试,适用于Robolectric 3.3.1