I'm trying to follow the examples in Spring in Action (4th edition), chapter 5 to create my own project. (Still a newbie at enterprise-level stuff) I'm using a Windows 7 PC, Java 7, Spring 4 and Maven. When I run my ClinicalNoteControllerTest, the test fails with a NoSuchMethod error on a specific line. But I've researched this line, and it seems to be written correctly. It definitely follows the example in the book. I've debugged, but can't find anything in what turns up there. I'm wondering if I don't have the correct configuration in my pom.xml file?
You guys are always so helpful, and I'll appreciate any help you can give finding a solution here. But I also want to become a better troubleshooter myself and not just run to stackoverflow every time I hit a bump. So any tips you can give on how I could troubleshoot this problem myself will be greatly appreciated.
Here is the test:
package com.kwalker.practicewellness;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import static org.hamcrest.Matchers.*;
import org.springframework.web.servlet.view.InternalResourceView;
import com.kwalker.practicewellness.data.ClinicalNoteRepository;
import com.kwalker.practicewellness.domain.ClinicalNote;
import com.kwalker.practicewellness.web.ClinicalNoteController;
public class ClinicalNoteControllerTest {
@Test
public void shouldShowRecentClinicalNotes() throws Exception {
List<ClinicalNote> expectedClinicalNotes = createClinicalNoteList(20);
ClinicalNoteRepository mockNoteRepository = mock(ClinicalNoteRepository.class);
when(mockNoteRepository.findClinicalNotes(Long.MAX_VALUE, 20)).thenReturn(expectedClinicalNotes);
ClinicalNoteController noteController = new ClinicalNoteController(mockNoteRepository);
MockMvc mockMvc = standaloneSetup(noteController).setSingleView(
new InternalResourceView("/WEB-INF/views/clinicalNotes.jsp")).build();
mockMvc.perform(get("/clinical-notes"))
.andExpect(view().name("clinicalNotes"))
.andExpect(model().attributeExists("clinicalNoteList"))
.andExpect(model().attribute("clinicalNoteList", hasItems(expectedClinicalNotes.toArray())));
}
private List<ClinicalNote> createClinicalNoteList(int count) {
List<ClinicalNote> clinicalNotes = new ArrayList<ClinicalNote>();
for (int i=0; i < count; i++) {
clinicalNotes.add(new ClinicalNote("Note " + i, new Date()));
}
return clinicalNotes;
}
}
Here is the ClinicalNoteController:
package com.kwalker.practicewellness.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.kwalker.practicewellness.data.ClinicalNoteRepository;
@Controller
@RequestMapping("/clinical-notes")
public class ClinicalNoteController {
private ClinicalNoteRepository noteRepository;
@Autowired
public ClinicalNoteController(ClinicalNoteRepository noteRepository) {
this.noteRepository = noteRepository;
}
@RequestMapping(method=RequestMethod.GET)
public String clinicalNotes(Model model) {
model.addAttribute("clinicalNoteList", noteRepository.findClinicalNotes(Long.MAX_VALUE, 20));
return "clinicalNotes";
}
}
Here is what prints out on the console when I run the test:
INFO : org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder$StaticRequestMappingHandlerMapping - Mapped "{[/clinical-notes],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String com.kwalker.practicewellness.web.ClinicalNoteController.clinicalNotes(org.springframework.ui.Model)
INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.test.web.servlet.setup.StubWebApplicationContext@41494678
INFO : org.springframework.mock.web.MockServletContext - Initializing Spring FrameworkServlet ''
INFO : org.springframework.test.web.servlet.TestDispatcherServlet - FrameworkServlet '': initialization started
INFO : org.springframework.test.web.servlet.TestDispatcherServlet - FrameworkServlet '': initialization completed in 16 ms
Here is the failure trace:
java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V
at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:31)
at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:14)
at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55)
at org.hamcrest.core.AllOf.matches(AllOf.java:24)
at org.springframework.test.util.MatcherAssertionErrors.assertThat(MatcherAssertionErrors.java:65)
at org.springframework.test.web.servlet.result.ModelResultMatchers$1.match(ModelResultMatchers.java:56)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:152)
at com.kwalker.practicewellness.ClinicalNoteControllerTest.shouldShowRecentClinicalNotes(ClinicalNoteControllerTest.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Here is my POM file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kwalker</groupId>
<artifactId>practicewellness</artifactId>
<name>Practice Wellness</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>1.7</java-version>
<org.springframework-version>4.1.4.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
</dependency>
<!-- Misc -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
Here is my webapp initializer:
package com.kwalker.practicewellness.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WellnessWebAppInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Here is my WebConfig file:
package com.kwalker.practicewellness.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan("com.kwalker.practicewellness.web")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Here is the RootConfig class:
package com.kwalker.practicewellness.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan(basePackages={"com.kwalker.practicewellness"},
excludeFilters={@Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)})
public class RootConfig {
}
This exact problem is addressed on Ted Vinke's blog from December 2013: Mixing JUnit, Hamcrest and Mockito
I used the code given on this page to modify my POM file (which basically involved rearranging mockito, junit and hamcrest, and excluding hamcrest on the mockito dependency). IMPORTANT TO NOTE: I was using the latest versions of these resources, and the fix DID NOT WORK until I made the versions in my POM file match the versions shown on the page at that link. Here is the text from the link:
This could be due to the fact that JUnit itself brings along its own version of Hamcrest as a transitive dependency. Now if you would be using JUnit 4.11 it would depending on Hamcrest 1.3 already.... Getting above error would be weird – since the describeMismatch method is present in org.hamcrest.Matcher interface. There seems to be an older version of org.hamcrest.Matcher present on the classpath to which org.junit.Assert.assertThat delegates. If you run this from Eclipse or IntelliJ, there’s a high chance that the IDE uses its own version of JUnit instead of your Maven dependency....
The article continues:
If we we’re looking in Eclipse for the Matcher classes we e.g. could see that there’s also one in mockito-all-1.9.5.jar.... Seems mockito-all is incompatible with JUnit 4.11 for backwards-compatibility reasons. The Hamcrest version 1.1 Matcher has been packaged within the dependency, so we can not exclude it.... Luckily for us, Mockito allows to us to use a mockito-core dependency instead of mockito-all. Running a dependency check (with dependency:tree or online) shows us it depends on hamcrest-core..... We can exclude it in the pom.xml and – no more NoSuchMethodError. Here’s the final combination of dependencies in our case:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With