【问题标题】:Unit Testing Internal State of Data Structure单元测试数据结构的内部状态
【发布时间】:2012-07-02 00:57:40
【问题描述】:

我的任务是为大量度量数据结构(即quadtreek-d tree 变体)创建实现。我已经完成了其中大约四个实现,但我目前正在测试的方式不是,因为我没有更好的词。

我需要一种干净的方法来测试从这些树/树结构中插入和删除数据的方式,以便我可以测试节点的内部结构(检查父级、子级、排序等)。这些实现遵循单独的正确性证明和运行时分析,因此我需要确保不仅正确插入节点(意思是稍后可以从树中检索),而且还要确保在树中非常“正确”的位置。

“单元测试”似乎是错误的方法,但是,如果我没记错的话,它的目的是测试结构或系统的外部 API。我见过很多与单元测试相关的问题,询问“如何在单元测试中访问私有字段”或“如何测试非公共方法的返回值”,答案通常是“不要” t" - 我同意这个答案。

所以我不会让任何人愿意帮助只是模糊的漫无边际,我的树实现的接口如下(基于 java 集合的 Map 接口):

public interface SpatialMap<K, V> extends Iterable<SpatialMap.Entry<K, V>>
{
// Query Operations

/**
 * Returns the number of key-value mappings in this map. If the map contains more than
 * <tt>Integer.MAX_VALUE</tt> elements, returns <tt>Integer.MAX_VALUE</tt>.
 * 
 * @return The number of key-value mappings in this map.
 */
int size();

/**
 * Returns <tt>true</tt> if this map contains no key-value mappings.
 * 
 * @return <tt>true</tt> if this map contains no key-value mappings.
 */
boolean isEmpty();

/**
 * Returns <tt>true</tt> if this map contains a mapping for the specified key.
 * 
 * @param key
 *            The key whose presence in this map is to be tested.
 * @return <tt>true</tt> if this map contains a mapping for the specified key.
 */
boolean containsKey(K key);

/**
 * Returns the value to which the specified key is mapped, or {@code null} if this map contains
 * no mapping for the key.
 * 
 * <p>A return value of {@code null} does not <i>necessarily</i> indicate that the map contains
 * no mapping for the key; it's also possible that the map explicitly maps the key to
 * {@code null}. The {@link #containsKey containsKey} operation may be used to distinguish these
 * two cases.
 * 
 * @see #put(Comparable, Comparable, Object)
 * 
 * @param key
 *            The key whose associated value is to be returned.
 * @return The value to which the specified key is mapped, or {@code null} if this map contains
 *         no mapping for the key.
 */
V get(K key);

// Modification Operations

/**
 * Associates the specified value with the specified key in this map. If the map previously
 * contained a mapping for the key, the old value is replaced.
 * 
 * @param key
 *            The key with which the specified value is to be associated.
 * @param data
 *            The value to be associated with the specified key.
 * @return The previous value associated with the key, or <tt>null</tt> if there was no mapping
 *         for the key. (A <tt>null</tt> return can also indicate that the map previously
 *         associated <tt>null</tt> with <tt>key</tt>.)
 */
V put(K key, V data);

/**
 * Removes the mapping for the specified key from this map if present.
 * 
 * @param key
 *            The key whose mapping is to be removed from the map.
 * @return The previous value associated with the key, or <tt>null</tt> if there was no mapping
 *         for the key. (A <tt>null</tt> return can also indicate that the map previously
 *         associated <tt>null</tt> with <tt>key</tt>.)
 */
V remove(K key);

// Bulk Operations

/**
 * Removes all of the mappings from this map. The map will be empty after this call returns.
 */
void clear();
}

这使得公共方法难以测试,因为我需要公共接口不可用的某些数据(子/父指针)。此外,在 trie 结构(PR Quadtree、PRKDTree、MX 变体等)中有与数据分离的节点,因此创建返回“节点”的公共方法也将被抽象得太远,无法获得正确的数据。

我在寻找哪种类型的测试方法(或我可以与 JUnit 一起使用且不会破坏美丽认知边界的技术)?

【问题讨论】:

    标签: java unit-testing data-structures


    【解决方案1】:

    在某些情况下,有时您确实需要测试结构的内部状态。在这种情况下,我将使用反射访问内部变量。有一些 JUnit 插件 (PrivateAccessor http://junit-addons.sourceforge.net/junitx/util/PrivateAccessor.html) 可以让这更容易。

    权衡是您的测试会更加脆弱,因为如果内部状态发生变化,那么您的测试可能会中断。但如果你想确信你的内部状态是正确的,有时你需要这样做。

    【讨论】:

    • 只要我的正确性证明实际上是正确的,就节点排序而言,内部状态永远不会改变;)
    • 是的,但是如果变量名称发生变化,例如测试可能会中断。这更像是一个白盒单元测试(相对于黑盒)。有时这种风格是合适的,在你的情况下,这就是你正在寻找的。​​span>
    【解决方案2】:

    我在这种情况下使用的一种方法是保护这些内部字段,并创建一个子类进行测试。通过该子类,您可以公开白盒测试所需的任何状态。

    【讨论】:

      【解决方案3】:

      如果您将接口及其实现单独放在专用包中,并使该实现的内部状态方法受包保护,那么您的测试可以访问它们,并可能测试它们,而您系统的其余部分则不能。

      这对于单元测试“纯粹主义者”来说并不好,但我通常是这样做的,当我不想将我的课程的内容暴露给系统的其余部分但我仍然想对它的内部行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-08
        • 2011-08-25
        • 1970-01-01
        相关资源
        最近更新 更多