English 中文(简体)
@InjectMocks与爪哇6和7的表现不同。
原标题:@InjectMocks behaving differently with Java 6 and 7

使用一个很简单的 Mocki至 运行 JUM 测试和等级, 当测试使用 Java 1. 60_ 32 和 Java 1. 0. 0. 0. 0_ 04 进行时, 我可以看到不同的输出, 并且想要理解 'em'why'/ em'it is happening this happening. 我怀疑正在发生某种类型的擦除, 但希望得到明确的答复 。

以下是我关于如何从指挥线上运行的示例代码和说明:

FooServiceTest.java

import org.junit.*;
import org.junit.runner.*;
import org.mocki至.*;
import org.mocki至.runners.Mocki至JUnitRunner;
import static org.mocki至.Mocki至.*;
import java.util.*;

@RunWith(Mocki至JUnitRunner.class)
public class FooServiceTest {
  @Mock Map<String, String> mockStringString;
  @Mock Map<String, Integer> mockStringInteger;

  @InjectMocks FooService fooService;

  public static void main(String[] args) {
    new JUnitCore().run(FooServiceTest.class);
  }

  @Before
  public void setup() {
    Mocki至Annotations.initMocks(this);
  }

  @Test
  public void checkInjection() {
    when(mockStringString.get("foo")).thenReturn("bar");
    fooService.println();
  }
}

FooService.java

import java.util.*;

public class FooService {
  private Map<String, String> stringString = new HashMap<String, String>();
  private Map<String, Integer> stringInteger = new HashMap<String, Integer>();

  public void println() {
    System.out.println(stringString.get("foo") + " " + stringInteger);
  }
}

要编译和运行此示例 :

  • save the above in至 files
  • download and put in the same direc至ry junit.4.10.jar and mocki至-all-1.9.0.jar
  • set PATH 至 include a JDK
  • compile with javac -cp junit-4.10.jar;mocki至-all-1.9.0.jar *.java
  • run with java -cp .;junit-4.10.jar;mocki至-all-1.9.0.jar FooServiceTest

我相信上面的输出是 null /code>,因为 实地注入无法正确解析这些类型, 因为两者都是类型的地图。 < 坚固> 这样正确吗 ?

现在更改一个模拟名称以匹配类中的字段, 允许 Mocki至 找到匹配。 例如, 更改

@Mock Map<String, Integer> mockStringInteger;

@Mock Map<String, Integer> stringInteger;

然后用 Java 1.6.0_32 提供(IMHO) 输出 < code> bar 字符串 Integer , 使用 1.7.0_04 提供 < code> null 字符串 。

以下是我是如何运行它(从Windows 7 的指令行):

E:srcmocki至-test>set PATH="C:Program Files (x86)Javajdk1.6.0_32in"
E:srcmocki至-test>javac -cp junit-4.10.jar;mocki至-all-1.9.0.jar *.java
E:srcmocki至-test>java -cp .;junit-4.10.jar;mocki至-all-1.9.0.jar FooServiceTest
    bar stringInteger
E:srcmocki至-test>set PATH="C:Program Files (x86)Javajdk1.7.0_04in"
E:srcmocki至-test>javac -cp junit-4.10.jar;mocki至-all-1.9.0.jar *.java
E:srcmocki至-test>java -cp .;junit-4.10.jar;mocki至-all-1.9.0.jar FooServiceTest
    null stringInteger
最佳回答

我相信上面的输出是无效的,因为 @InjectMocks 实地注射无法正确解决类型问题, 因为两者都是型号地图。 这是否正确?

是的,正确的这些领域莫基托无法澄清模棱两可之处,所以它只是忽略了这些模棱两可的领域。

使用简单的 Mockito 运行 JUM 测试和类, 当测试使用 Java 1. 60_ 32 和 Java 1. 7. 0_ 04 进行时, 我可以看到不同的输出, 并想知道为什么会发生这种情况 。

事实上,变异存在于 Arrays.sort 的不同行为中, 因此在 JDK 6 与 JDK 7. 7 之间, 收藏.sort () 不同的行为中。 区别在于新的代数法, 该代数应比交换少20%。 这个互换操作可能让事物在 JDK 6 和 JDK 7 下起作用 。

如果您只重命名一个相同类型(或同一擦拭)的字段的模拟字段,您可能就是“寻找麻烦 ” 。 当模拟无法按类型区分时, 您应该将所有模拟字段都命名为相应的字段, 但 Javadoc 并没有明确指出这一点 。

感谢您在Mockito < / a > 上报导怪异行为, 我创建了一个< a href="https://code.google.com/p/mockito/issues/detail?id=353" rel=“norefererr” >issues on Mockito , 但现在我无法真正解决这个问题, 而是确保整个JDKs都有同样的行为。 解决这个问题可能需要在保持兼容性的同时, 将新的代数编码成一个新的代数, 在您应该将所有域命名为“ 测试类” 的域时, 。

现在要做的工作很可能是用额外的比较来调整比较国,以便对JDK6和JDK7执行同样的命令。 此外,在Javadoc中又增加了一些警告。

" 强力 " EDIT

希望有帮助 找出问题的关键


另外,您需要 MockitoAntotations.initMocks( this); 或运行者 的方式,使用这两种方法都没有必要,甚至可能造成一些问题。 ) :

问题回答

Mockito 的行为是没有定义的, 如果有一个以上的模型可以匹配要注入的字段之一 。 这里, “ 配方” 表示它是正确的类型, 忽略任何类型的参数 - 类型擦除使 Mokito 无法知道类型参数 。 因此, 在您的例子中, 两个模型中的任何一个都可以被注入到两个字段中的任何一个 。

您对 Java 7 的 Java 6 观察到不同行为, 有点像红鹿。 在 Java 7 的两种版本中, 都没有理由期望 Mockito 正确选择它注射的两个字段中的任何一个 : < code> mock string 或 < code> mockStringStringInteger 。

" 强 " 是否正确?

事实上,由于,“http://docs.oracle.com/javase/tuative/java/generics/erasure.html' rel=“nofollow” > 类型擦除 ,Mockito无法通过反射看到各种地图在运行时/通过反射的不同,这使Mockito很难打针。

null responsion to string String.get (“foo”) 有两个原因:

  1. stringString properly mocked, but stubbing did not take place (get always return null).
  2. stringString not mocked, so still a HashMap without a value for "foo", so get will return null.

_/code> 对 stringInteger 变量的响应表示它已经(在类中)与实际(空)HashMap 初始化。

所以,您的输出告诉您的是, stringstringInteger 不被嘲笑。 那么 string 怎么办?

如果两个 中没有一个名称与所测试的类别的任何字段匹配, 则没有被嘲笑。 原因是什么? 我怀疑它不能决定要输入哪个字段, 所以它不会做任何模拟 。 您可以通过显示两个变量来验证这一点, 这两个变量都会产生 < code\\\\/ code > 。 这解释了您的 < code> null 值 。

如果一个 具有匹配的名称,而另一个则有不匹配的名称(您修改的名称,一个 mockedString String 和一个 stringstringInteger ,即具有相同的名称),那么Mockito应该怎么做?

您想要它做的只是输入其中的一个, 并且只在字段中输入相应的名称 < em> 。 在您的情况中, 您有 < code> mockedString string (您会期望这不会匹配) 和 < code> string (您会期待它匹配) 。 由于您将 < code> mockedString (!) 粘贴到匹配的 < code> string (!), < em > 预期结果将是 < codenull

换句话说,我认为Java 7的回答是好的,而Java 6的回答是不好的,就具体的例子而言。

要看到 Java 6 的( 意外) 行为正在发生什么( 意外) 行为, 请尝试只尝试一个 < code @ mock -- -- 如果我适当地嘲笑 < code> string , 并且有 < em> no < / em > 模拟 < code > string Integer , 那么 < code> string 的模型就会被注入到 < code> string < / code > 字段中。 换句话说, Mockito似乎首先发现它可以输入( 给名称), 然后将模型输入匹配的可能性之一( 但不一定正确 ) 。





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...