Let’s write some actual code that we will use for visualization.

To visualize mocked object we should collect the creation of the mocks in the class or method you are interested in.
So we need to evaluate the code to find method calls that creates mocks in Mockito framework.
The simplest way to evaluate AST is to create an ASTVisitor. AST parser will generate the AST from code but it is not the only thing that it normally does. It also binds symbols to declarations. The problem with that is that the AST parser have to be in position to look up all declarations and this is a problem if you just want to provide a snippet of code.

So any way, here is the test class for visitor witch should find creations of mocked objects.

public class TestFindMockedObjects {
 
	private Block ast;
	private BindingHandler bindingHandler;
	private List<MockedObject> foundMocks;
 
	@Test
	public void canFindMock() throws Exception {
		String javaCode = "A a = mock(A.class);";
		setup(javaCode);
		when(bindingHandler.getTypeName(Matchers.any(Type.class))).thenReturn("A");
		findMocks();
		assertThat(foundMocks.isEmpty(), is(false));
	}
 
	@Test
	public void canFindMockWithProperName() throws Exception {
		String javaCode = "A a = mock(A.class);";
		setup(javaCode);
		when(bindingHandler.getTypeName(any(Type.class))).thenReturn("A");
		findMocks();
		assertThat(foundMocks.get(0).getObjectName(), is("a"));
		assertThat(foundMocks.get(0).getTypeName(), is("A"));
	}
 
	@Test
	public void canFindMockInAssignment() throws Exception {
		String javaCode = "A a; a = mock(A.class);";
		setup(javaCode);
		when(bindingHandler.getTypeName(Matchers.any(Type.class))).thenReturn("A");
		findMocks();
		assertThat(foundMocks.isEmpty(), is(false));
	}
 
	@Test
	public void canFindMocksWithProperNamesForDeclarationAndAssignment() throws Exception {
		String javaCode = "A a1 = mock(A.class); B b2; b2 = mock(B.class);";
		setup(javaCode);
		when(bindingHandler.getTypeName(any(Type.class))).thenReturn("A");
		when(bindingHandler.getTypeName(any(Expression.class))).thenReturn("B");
		findMocks();
		assertThat(foundMocks.get(0).getObjectName(), is("a1"));
		assertThat(foundMocks.get(0).getTypeName(), is("A"));
		assertThat(foundMocks.get(1).getObjectName(), is("b2"));
		assertThat(foundMocks.get(1).getTypeName(), is("B"));
	}
 
	@Test
	public void canFindMockAlsoIfItIsASpy() throws Exception {
		String javaCode = "A a = spy(new A());";
		setup(javaCode);
		when(bindingHandler.getTypeName(Matchers.any(Type.class))).thenReturn("A");
		findMocks();
		assertThat(foundMocks.isEmpty(), is(false));
	}
 
	private void setup(String javaCode) {
		createAst(javaCode);
		prepareBindingHandler();
	}
 
	private void createAst(String javaCode) {
		ASTParser newParser = ASTParser.newParser(AST.JLS3);
		newParser.setKind(ASTParser.K_STATEMENTS);
		newParser.setSource(javaCode.toCharArray());
		ast = (Block)newParser.createAST(new NullProgressMonitor());
	}
 
	private void prepareBindingHandler(){
		bindingHandler = mock(BindingHandler.class);
	}
 
	private void findMocks() {
		FindMockedObjects finder = new FindMockedObjects();
		finder.setBindingHandler(bindingHandler);
		ast.accept(finder);
		foundMocks = finder.getFoundMocks();
	}
}

I created no @Before method because the state I am testing on is different from test to test. So I am reusing by extracting the logic in private methods and calling them in every test with different parameters. I have to copy and paste code though. This problem will be addressed in next posts.

So any way, the visitor can evaluate the AST, but we also need it to be binded because of Type name of mocked object.

	@Override
	public boolean visit(MethodInvocation node) {
		if(isMockingMethod(node)){
			VariableDeclaration variableDecl = getParent(node, VariableDeclarationFragment.class);
			if(variableDecl != null){
				String objectName = variableDecl.getName().getIdentifier();
				VariableDeclarationStatement parent = getParent(variableDecl, VariableDeclarationStatement.class);
				Type type = parent.getType();
				foundMocks.add(new MockedObject(objectName, bindingHandler.getTypeName(type)));
				return true;
			}
			Assignment assignment = getParent(node, Assignment.class);
			if(assignment!=null){
				Expression leftHandSide = assignment.getLeftHandSide();
				if(leftHandSide instanceof SimpleName){
					SimpleName name = (SimpleName)leftHandSide;
					foundMocks.add(new MockedObject(name.getIdentifier(), bindingHandler.getTypeName(leftHandSide)));
					return true;
				}
 
			}
		}
 
		return true;
	}

So I extracted the logic that is depends on AST binding and put it in an extra class that I am mocking out in Test.

...
bindingHandler = mock(BindingHandler.class);
...
FindMockedObjects finder = new FindMockedObjects();
finder.setBindingHandler(bindingHandler);
...
when(bindingHandler.getTypeName(Matchers.any(Type.class))).thenReturn("A");
...

This way I can concentrate myself on the actual AST visiting and check binding resolving.
I another test.

Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Before you submit form:
Human test by Not Captcha

© 2011 Max Blog Suffusion theme by Sayontan Sinha