[关闭]
@weixin 2014-11-23T16:05:11.000000Z 字数 6415 阅读 1392

Jmocke study notes 4

mock


Class Initialization mock up

Ex 1

  1. static class ClassWithStaticInitializer1
  2. {
  3. static final String CONSTANT = new String("not a compile-time constant");
  4. static String variable;
  5. static { variable = doSomething(); }
  6. static String doSomething() { return "real value"; }
  7. }
  8. @Test
  9. public void mockClassWithStaticInitializerNotStubbedOut(@Mocked/*(stubOutClassInitialization = true)*/
  10. ClassWithStaticInitializer1 mocked) {
  11. assertNotNull(ClassWithStaticInitializer1.CONSTANT);
  12. assertNull(ClassWithStaticInitializer1.doSomething());
  13. // assertEquals("real value", ClassWithStaticInitializer1.variable);
  14. assertNull("it is null", ClassWithStaticInitializer1.variable);
  15. }

notice the code I comment out /*(stubOutClassInitialization = true)*/, if I uncomment it, the test would failed at line assertNotNull(ClassWithStaticInitializer1.CONSTANT);, CONSTANT would become null.

Ex2

another very similar example,

  1. static class ClassWithStaticInitializer2
  2. {
  3. static final String CONSTANT = new String("not a compile-time constant");
  4. static { doSomething(); }
  5. static void doSomething() { throw new UnsupportedOperationException("must not execute"); }
  6. }
  7. @Test
  8. public void useClassWithStaticInitializerNeverStubbedOutAndNotMockedNow()
  9. {
  10. // Allows the class to be initialized without throwing the exception.
  11. MockUp<?> mockUp = new MockUp<ClassWithStaticInitializer2>() {
  12. /* @Mock
  13. void $clinit() {}*/
  14. @Mock void doSomething() {} };
  15. // Initializes the class:
  16. assertNotNull(ClassWithStaticInitializer2.CONSTANT);
  17. // Restore the now initialized class:
  18. mockUp.tearDown();
  19. try {
  20. ClassWithStaticInitializer2.doSomething();
  21. fail();
  22. }
  23. catch (UnsupportedOperationException ignore) {}
  24. }

be aware of this part of code snippet,@Mock void $clinit() {}, without commenting it, this line would also fail : assertNotNull(ClassWithStaticInitializer2.CONSTANT);

Ex3

  1. static class ClassWhichCallsStaticMethodFromInitializer
  2. {
  3. static {
  4. String s = someValue();
  5. s.length();
  6. }
  7. static String someValue() { return "some value"; }
  8. }
  9. @Test
  10. public void mockUninitializedClass(@Mocked ClassWhichCallsStaticMethodFromInitializer unused)
  11. {
  12. assertNull(ClassWhichCallsStaticMethodFromInitializer.someValue());
  13. }
  14. @Test
  15. public void mockInitializedClass()
  16. {
  17. MockUp<?> mockup = new MockUp<ClassWhichCallsStaticMethodFromInitializer>(){
  18. @Mock
  19. void $clinit() {}
  20. @Mock
  21. String someValue() {return "hi";}
  22. };
  23. assertNotNull(ClassWhichCallsStaticMethodFromInitializer.someValue());
  24. mockup.tearDown();
  25. assertEquals("some value", ClassWhichCallsStaticMethodFromInitializer.someValue());
  26. }

EX4

  1. @Deprecated
  2. static final class Collaborator
  3. {
  4. @Deprecated final boolean b;
  5. @Deprecated Collaborator() { b = false; }
  6. Collaborator(boolean b) { this.b = b; }
  7. @Ignore("test") int doSomething(@Deprecated String s) { return s.length(); }
  8. <N extends Number> N genericMethod(@SuppressWarnings("unused") N n) { return null; }
  9. @Deprecated static boolean doSomethingElse() { return false; }
  10. }
  11. @Test
  12. public void attemptToCreateMockUpWithMockMethodLackingCorrespondingRealMethod()
  13. {
  14. // thrown.expect(IllegalArgumentException.class);
  15. // thrown.expectMessage("$init(int i");
  16. // put aa instantialization won't print any thing
  17. Collaborator aa = new Collaborator();
  18. new MockUp<Collaborator>() { @Mock
  19. // void $init(int i) { System.out.println(i); } };
  20. void $init() { System.out.println("i am hero..."); } };
  21. // ba would print out in console
  22. Collaborator ba = new Collaborator();
  23. }

notice , mock init(int i) is wrong, because Collaborator doesn't have a such a constructor

EX5

  1. static final class Main
  2. {
  3. static final AtomicIntegerFieldUpdater<Main> atomicCount =
  4. AtomicIntegerFieldUpdater.newUpdater(Main.class, "count");
  5. volatile int count;
  6. int max = 2;
  7. boolean increment()
  8. {
  9. while (true) {
  10. int currentCount = count;
  11. if (currentCount >= max) {
  12. return false;
  13. }
  14. if (atomicCount.compareAndSet(this, currentCount, currentCount + 1)) {
  15. return true;
  16. }
  17. }
  18. }
  19. }
  20. @Test
  21. public void mockUpGivenClass()
  22. {
  23. final Main main = new Main();
  24. AtomicIntegerFieldUpdater<?> atomicCount = Deencapsulation.getField(Main.class, AtomicIntegerFieldUpdater.class);
  25. new MockUp<AtomicIntegerFieldUpdater<?>>(atomicCount.getClass()) {
  26. boolean second;
  27. @Mock(invocations = 2)
  28. public boolean compareAndSet(Object obj, int expect, int update)
  29. {
  30. assertSame(main, obj);
  31. assertEquals(0, expect);
  32. assertEquals(1, update);
  33. if (second) {
  34. return true;
  35. }
  36. second = true;
  37. return false;
  38. }
  39. };
  40. assertTrue(main.increment());
  41. }

protected MockUp(Class<?> classToMock)
Applies the mock methods defined in the mock-up subclass to the given class/interface.

given a type, then a particular class, you can mock that given class, this is what new MockUp<AtomicIntegerFieldUpdater<?>>(atomicCount.getClass()) { does

why compareAndSet has a anotation - invocations=2?

  1. call increament. notice the inside the increment there is a while loop.
  2. goes to the if block, this is the first time of compareAndSet got called.
  3. goes to the mocked implementation, by default, second is false, so second = true; return false
  4. goes to the while again. the compareAndSet would be called again, this time, it would return true, and the code returned from while loop finally.

EX6

  1. @Test
  2. public void mockUpUsingInvocationParameters()
  3. {
  4. new MockUp<Collaborator>() {
  5. @Mock(invocations = 1)
  6. void $init(Invocation inv, boolean b)
  7. {
  8. Collaborator it = inv.getInvokedInstance();
  9. assertFalse(it.b);
  10. assertTrue(b);
  11. }
  12. @Mock
  13. int doSomething(Invocation inv, String s)
  14. {
  15. return inv.proceed(s + ": mocked");
  16. }
  17. };
  18. int i = new Collaborator(true).doSomething("test");
  19. assertEquals(12, i);
  20. }

notice the usage of invocation parameters, it would call the real implementation. For this code:

  1. Collaborator it = inv.getInvokedInstance();
  2. assertFalse(it.b);
  3. assertTrue(b);

I don't know why it.b is false?

Then I put some diagnostic output there:

  1. @Test
  2. public void mockUpUsingInvocationParameters()
  3. {
  4. new MockUp<Collaborator>() {
  5. @Mock(invocations = 1)
  6. void $init(Invocation inv, boolean b)
  7. {
  8. Collaborator it = inv.getInvokedInstance();
  9. System.out.println(it.hashCode());
  10. System.out.println(it.toString());
  11. assertFalse(it.b);
  12. assertTrue(b);
  13. }
  14. @Mock
  15. int doSomething(Invocation inv, String s)
  16. {
  17. return inv.proceed(s + ": mocked");
  18. }
  19. };
  20. Collaborator aa = new Collaborator(true);
  21. System.out.println(aa.hashCode());
  22. System.out.println(aa.toString());
  23. if(aa.b)
  24. {
  25. System.out.println("it is true..");
  26. }
  27. else
  28. {
  29. System.out.println("it is false..");
  30. }
  31. int i = aa.doSomething("test");
  32. // int i = new Collaborator(true).doSomething("test");
  33. assertEquals(12, i);
  34. }

the output is like this:

  1. 315208913
  2. com.weixin.test.MockUpTest$Collaborator@12c9b4d1
  3. 315208913
  4. com.weixin.test.MockUpTest$Collaborator@12c9b4d1
  5. it is false..
  6. Tests run: 1,

in fact, it is very simple, because we also mocked the boolean constructor, so the original constructor doesn't get executed. this.b=b doens't run. Also you could see the inv.getInvokedInstace() return the exact instance of aa.

Ex 7

  1. static class Outer
  2. {
  3. class Inner
  4. {
  5. final int value;
  6. Inner(int value) { this.value = value; }
  7. }
  8. }
  9. @Test
  10. public void mockConstructorOfInnerClass()
  11. {
  12. final Outer outer = new Outer();
  13. new MockUp<Outer.Inner>() {
  14. @Mock void $init(Outer o, int i)
  15. {
  16. assertSame(outer, o);
  17. assertEquals(123, i);
  18. }
  19. };
  20. Outer.Inner inner = outer.new Inner(123);
  21. assertEquals(0, inner.value);
  22. }

notice how to mockup a inner class.

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注