Java 如何测试列表是否<;?扩展对象>;他是一个非编撰者吗?
我正在寻找一种方法来测试某个给定的列表是否是不可修改的 我有一个对象,它有一个Java 如何测试列表是否<;?扩展对象>;他是一个非编撰者吗?,java,unit-testing,collections,tdd,Java,Unit Testing,Collections,Tdd,我正在寻找一种方法来测试某个给定的列表是否是不可修改的 我有一个对象,它有一个列表,以便提供诸如addNoMatter(NoMatter nm)之类的方法,而不是允许API客户端简单地执行.getNoMatters().add(nm)我总是返回此列表的不可修改版本,因此客户端仍然可以拥有该列表。我的做法如下: public List<NoMatter> getNoMatters() { return Collections.unmodifiableList(this.noMa
列表
,以便提供诸如addNoMatter(NoMatter nm)
之类的方法,而不是允许API客户端简单地执行.getNoMatters().add(nm)代码>我总是返回此列表的不可修改版本,因此客户端仍然可以拥有该列表。我的做法如下:
public List<NoMatter> getNoMatters() {
return Collections.unmodifiableList(this.noMatters);
}
碰巧我似乎无法导入类型UnmodifiableList
也无法导入java.util.Collections$UnmodifiableRandomAccessList
,这就是我尝试System.out.println(myObj.getNoMatters().getClass().getName())时得到的结果代码>在控制台上
那么我怎样才能做到呢
注:我知道我可以通过以下测试:
@Test(expected = UnsupportedOperationException.class)
public void checkIfListIsImmutable(){
this.myObj.getNoMatters().add(null);
}
编辑:上面的测试并不能保证我处理的列表不是不变的,因为我需要对可能修改我原始列表的每个方法进行测试,包括.remove()、.clear()、.shuffle()等!这就是为什么我不认为这是一个好的方式进行
>>>但我仍然相信,它甚至不接近一个优雅的解决方案 我真的认为这是你最好的选择。另一种(不那么优雅的)方法是检查类的名称
this.myObj.getNoMatters().getClass().getSimpleName().equals("UnmodifiableCollection")
问题是包装的不可修改集合是包私有的
我不认为期待出现异常有什么错,但那只是我。我认为您的解决方案不仅合理,而且优雅。您希望测试您不能修改列表,并且您的测试简洁地证明了这一点。测试类的名称测试名称,而不是行为。在这种情况下,谁在乎名字
同样,如果我想测试我不能将null传递给某个方法,我会在测试中传递null,并期望出现IllegalArgumentException。有点像黑客,但请尝试:
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Integer> list=new LinkedList<Integer>();
list.add(1);
List<Integer> unmodifiableList=Collections.unmodifiableList(list);
System.out.println(unmodifiableList.getClass());
if(unmodifiableList.getClass().getName().contains("UnmodifiableList"))
System.out.println(true);
}
}
import java.util.*;
公共班机{
公共静态void main(字符串[]args){
列表=新建LinkedList();
增加第(1)款;
列表不可修改列表=集合。不可修改列表(列表);
System.out.println(unmodifiableList.getClass());
if(unmodifiableList.getClass().getName()包含(“unmodifiableList”))
System.out.println(真);
}
}
您可以使用来检查
Collections.unmodifiableList(someList).getClass().isInstance(listToCheck);
/e1
下面返回false
Collections.unmodifiableList(new ArrayList<Object>()).getClass().isInstance(new ArrayList<Object>())
/e2
您的问题可能是因为Collections#unmodifiableList
在某些时间返回unmodifiableList
,在其余时间返回UnmodifiableRandomAccessList
(代码见下文)。然而,由于UnmodifiableRandomAccessList
扩展了UnmodifiableList
,如果您得到一个UnmodifiableList
的实例进行检查,您将获得金牌
要获取UnmodifiableList
的实例,可以使用Collections.UnmodifiableList(newlinkedlist())
LinkedList
未实现RandomAccess
,因此不会返回UnmodifiableRandomAccessList
的实例
集合的代码#不可修改列表
:
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof RandomAccess ?
new UnmodifiableRandomAccessList<>(list) :
new UnmodifiableList<>(list));
}
static class UnmodifiableRandomAccessList<E> extends UnmodifiableList<E> implements RandomAccess
为什么要测试列表是不可变的?您的“替代”解决方案是一条路:您应该专注于测试类的行为,而不是它的状态
我的意思是,您并不真正关心您的方法是否返回UnmodifiableList
的实例或其他任何东西。谁在乎呢?你的测试当然不应该。如果以后更改实现以实现完全相同的行为,您的测试不应失败
那么你想测试什么呢?用户无法向列表中添加任何内容?然后编写一个测试(如您所建议的),向列表中添加一些内容,并期望出现异常。他们不能从列表中删除任何内容?对另一个测试进行同样的操作。等等
测试像这样的负面案例确实很优雅,我发现在类的函数覆盖中经常会忘记它。适当的覆盖范围应明确说明您的类不允许的内容,并说明在这些情况下的预期内容。我希望类似于集合的内容。检查(T元素)
在不实际修改集合的情况下完成工作
除了投票最多的答案外,还有Collections.EmptyList
(至少)这是另一个不可修改的列表
因此,如果我真的必须创建一个实用程序作为一个肮脏的解决方案,我将添加我的“易于识别”元素,看看它是否抛出UnsupportedOperationException,那么这意味着它是不可修改的。否则,我必须立即删除输入的内容。除了回答之外,还说明确实应该对行为进行测试,并包括作者的评论,他建议添加一个空列表,以便在列表不是不可修改的情况下不会被修改,我在这里添加了一个示例,说明如何检查列表的不可修改性
代码尝试添加一个空列表,如果可能的话,抛出一个IllegalArgumentException,否则为了方便起见,返回原始列表,现在可以确保它是不可修改的
/**
* Ensures that a list is unmodifiable (i.e. that nothing can be added).
*
* Unmodifiable lists can e.g. be created by Collections.UnmodifiableList().
*
* @param list a list
* @param <T> element type of the list
* @return the list that is verified to be unmodifiable
*/
public static <T> List<T> verifyUnmodifiable(List<T> list) {
try {
list.addAll(Collections.emptyList());
} catch (Exception e) {
return list;
}
throw new IllegalArgumentException("List is modifiable.");
}
/**
*确保列表不可修改(即不能添加任何内容)。
*
*例如,不可修改列表可以由集合创建。不可修改列表()。
*
*@param列出一个列表
*@param列表的元素类型
*@返回经验证不可修改的列表
*/
公共静态列表验证不可修改(列表列表){
试一试{
list.addAll(Collections.emptyList());
}捕获(例外e){
退货清单;
}
抛出新的IllegalArgumentException(“列表可修改”);
}
不确定是否测试移除、清除。。。这也是必要的。不能添加通常是不可修改的一个很好的指示。如果API很难测试,这通常是一种API需要改进的气味。在里面
static class UnmodifiableRandomAccessList<E> extends UnmodifiableList<E> implements RandomAccess
/**
* Ensures that a list is unmodifiable (i.e. that nothing can be added).
*
* Unmodifiable lists can e.g. be created by Collections.UnmodifiableList().
*
* @param list a list
* @param <T> element type of the list
* @return the list that is verified to be unmodifiable
*/
public static <T> List<T> verifyUnmodifiable(List<T> list) {
try {
list.addAll(Collections.emptyList());
} catch (Exception e) {
return list;
}
throw new IllegalArgumentException("List is modifiable.");
}