ContextConfiguration dosen't work JUnit4 class for testbench - unit-testing

Hello I am finding the solution for getting the bean instantiated given in #ContextConfiguration when we run the Vaadin test case with spring boot.
Here is some piece of the code which I have configured.
#WebAppConfiguration
#RunWith(JUnit4.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = UIConfiguration.class)
public abstract class BaseTestCase extends TestBenchTestCase {
//code stuff
}
#Configuration
#PropertySource("classpath:META-INF/spring/application.properties")
#ComponentScan(basePackages = "com.ui", excludeFilters = #ComponentScan.Filter(value = Controller.class, type = FilterType.ANNOTATION))
#EnableAsync
#EnableI18N
public class UIConfiguration implements AsyncConfigurer {
//block of code
}

You should be able to use the ClassRule and Rule Spring provide if you do not want to use the SpringRunner
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
See the java doc for more details,
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/junit4/rules/SpringClassRule.html
SpringClassRule is a custom JUnit TestRule that supports class-level features of the Spring TestContext Framework in standard JUnit tests by means of the TestContextManager and associated support classes and annotations.
In contrast to the SpringJUnit4ClassRunner, Spring's rule-based JUnit support has the advantage that it is independent of any Runner and can therefore be combined with existing alternative runners like JUnit's Parameterized or third-party runners such as the MockitoJUnitRunner.
In order to achieve the same functionality as the SpringJUnit4ClassRunner, however, a SpringClassRule must be combined with a SpringMethodRule, since SpringClassRule only supports the class-level features of the SpringJUnit4ClassRunner.

Related

Mockito cannot mock/spy because final class [duplicate]

I have a final class, something like this:
public final class RainOnTrees{
public void startRain(){
// some code here
}
}
I am using this class in some other class like this:
public class Seasons{
RainOnTrees rain = new RainOnTrees();
public void findSeasonAndRain(){
rain.startRain();
}
}
and in my JUnit test class for Seasons.java I want to mock the RainOnTrees class. How can I do this with Mockito?
Mocking final/static classes/methods is possible with Mockito v2 only.
add this in your gradle file:
testImplementation 'org.mockito:mockito-inline:2.13.0'
This is not possible with Mockito v1, from the Mockito FAQ:
What are the limitations of Mockito
Needs java 1.5+
Cannot mock final classes
...
Mockito 2 now supports final classes and methods!
But for now that's an "incubating" feature. It requires some steps to activate it which are described in What's New in Mockito 2:
Mocking of final classes and methods is an incubating, opt-in feature. It uses a combination of Java agent instrumentation and subclassing in order to enable mockability of these types. As this works differently to our current mechanism and this one has different limitations and as we want to gather experience and user feedback, this feature had to be explicitly activated to be available ; it can be done via the mockito extension mechanism by creating the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
After you created this file, Mockito will automatically use this new engine and one can do :
final class FinalClass {
final String finalMethod() { return "something"; }
}
FinalClass concrete = new FinalClass();
FinalClass mock = mock(FinalClass.class);
given(mock.finalMethod()).willReturn("not anymore");
assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());
In subsequent milestones, the team will bring a programmatic way of using this feature. We will identify and provide support for all unmockable scenarios. Stay tuned and please let us know what you think of this feature!
add this in your build file:
if using gradle: build.gradle
testImplementation 'org.mockito:mockito-inline:2.13.0'
if using maven: pom.xml
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>2.13.0</version>
<scope>test</scope>
</dependency>
this is a configuration to make mockito work with final classes
If you faced the Could not initialize inline Byte Buddy mock maker. (This mock maker is not supported on Android.)
Add the Byte Buddy dependency to your build.gradle file:
testImplementation 'net.bytebuddy:byte-buddy-agent:1.10.19'
src: https://mvnrepository.com/artifact/net.bytebuddy/byte-buddy
You cannot mock a final class with Mockito, as you can't do it by yourself.
What I do, is to create a non-final class to wrap the final class and use as delegate. An example of this is TwitterFactory class, and this is my mockable class:
public class TwitterFactory {
private final twitter4j.TwitterFactory factory;
public TwitterFactory() {
factory = new twitter4j.TwitterFactory();
}
public Twitter getInstance(User user) {
return factory.getInstance(accessToken(user));
}
private AccessToken accessToken(User user) {
return new AccessToken(user.getAccessToken(), user.getAccessTokenSecret());
}
public Twitter getInstance() {
return factory.getInstance();
}
}
The disadvantage is that there is a lot of boilerplate code; the advantage is that you can add some methods that may relate to your application business (like the getInstance that is taking a user instead of an accessToken, in the above case).
In your case I would create a non-final RainOnTrees class that delegate to the final class. Or, if you can make it non-final, it would be better.
In Mockito 3 and more I have the same problem and fixed it as from this link
Mock Final Classes and Methods with Mockito
as follow
Before Mockito can be used for mocking final classes and methods, it needs to be > configured.
We need to add a text file to the project's src/test/resources/mockito-extensions directory named org.mockito.plugins.MockMaker and add a single line of text:
mock-maker-inline
Mockito checks the extensions directory for configuration files when it is loaded. This file enables the mocking of final methods and classes.
Use Powermock. This link shows, how to do it: https://github.com/jayway/powermock/wiki/MockFinal
Just to follow up. Please add this line to your gradle file:
testCompile group: 'org.mockito', name: 'mockito-inline', version: '2.8.9'
I have tried various version of mockito-core and mockito-all. Neither of them work.
I had the same problem. Since the class I was trying to mock was a simple class, I simply created an instance of it and returned that.
I guess you made it final because you want to prevent other classes from extending RainOnTrees. As Effective Java suggests (item 15), there's another way to keep a class close for extension without making it final:
Remove the final keyword;
Make its constructor private. No class will be able to extend it because it won't be able to call the super constructor;
Create a static factory method to instantiate your class.
// No more final keyword here.
public class RainOnTrees {
public static RainOnTrees newInstance() {
return new RainOnTrees();
}
private RainOnTrees() {
// Private constructor.
}
public void startRain() {
// some code here
}
}
By using this strategy, you'll be able to use Mockito and keep your class closed for extension with little boilerplate code.
Another workaround, which may apply in some cases, is to create an interface that is implemented by that final class, change the code to use the interface instead of the concrete class and then mock the interface. This lets you separate the contract (interface) from the implementation (final class). Of course, if what you want is really to bind to the final class, this will not apply.
Time saver for people who are facing the same issue (Mockito + Final Class) on Android + Kotlin. As in Kotlin classes are final by default. I found a solution in one of Google Android samples with Architecture component. Solution picked from here : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample
Create following annotations :
/**
* This annotation allows us to open some classes for mocking purposes while they are final in
* release builds.
*/
#Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class OpenClass
/**
* Annotate a class with [OpenForTesting] if you want it to be extendable in debug builds.
*/
#OpenClass
#Target(AnnotationTarget.CLASS)
annotation class OpenForTesting
Modify your gradle file. Take example from here : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/build.gradle
apply plugin: 'kotlin-allopen'
allOpen {
// allows mocking for classes w/o directly opening them for release builds
annotation 'com.android.example.github.testing.OpenClass'
}
Now you can annotate any class to make it open for testing :
#OpenForTesting
class RepoRepository
Actually there is one way, which I use for spying. It would work for you only if two preconditions are satisfied:
You use some kind of DI to inject an instance of final class
Final class implements an interface
Please recall Item 16 from Effective Java. You may create a wrapper (not final) and forward all call to the instance of final class:
public final class RainOnTrees implement IRainOnTrees {
#Override public void startRain() { // some code here }
}
public class RainOnTreesWrapper implement IRainOnTrees {
private IRainOnTrees delegate;
public RainOnTreesWrapper(IRainOnTrees delegate) {this.delegate = delegate;}
#Override public void startRain() { delegate.startRain(); }
}
Now not only can you mock your final class but also spy on it:
public class Seasons{
RainOnTrees rain;
public Seasons(IRainOnTrees rain) { this.rain = rain; };
public void findSeasonAndRain(){
rain.startRain();
}
}
IRainOnTrees rain = spy(new RainOnTreesWrapper(new RainOnTrees()) // or mock(IRainOnTrees.class)
doNothing().when(rain).startRain();
new Seasons(rain).findSeasonAndRain();
Give this a try:
Mockito.mock(SomeMockableType.class,AdditionalAnswers.delegatesTo(someInstanceThatIsNotMockableOrSpyable));
It worked for me. "SomeMockableType.class" is the parent class of what you want to mock or spy, and someInstanceThatIsNotMockableOrSpyable is the actual class that you want to mock or spy.
For more details have a look here
This can be done if you are using Mockito2, with the new incubating feature which supports mocking of final classes & methods.
Key points to note:
1. Create a simple file with the name “org.mockito.plugins.MockMaker” and place it in a folder named “mockito-extensions”. This folder should be made available on the classpath.
2. The content of the file created above should be a single line as given below:
mock-maker-inline
The above two steps are required in order to activate the mockito extension mechanism and use this opt-in feature.
Sample classes are as follows:-
FinalClass.java
public final class FinalClass {
public final String hello(){
System.out.println("Final class says Hello!!!");
return "0";
}
}
Foo.java
public class Foo {
public String executeFinal(FinalClass finalClass){
return finalClass.hello();
}
}
FooTest.java
public class FooTest {
#Test
public void testFinalClass(){
// Instantiate the class under test.
Foo foo = new Foo();
// Instantiate the external dependency
FinalClass realFinalClass = new FinalClass();
// Create mock object for the final class.
FinalClass mockedFinalClass = mock(FinalClass.class);
// Provide stub for mocked object.
when(mockedFinalClass.hello()).thenReturn("1");
// assert
assertEquals("0", foo.executeFinal(realFinalClass));
assertEquals("1", foo.executeFinal(mockedFinalClass));
}
}
Hope it helps.
Complete article present here mocking-the-unmockable.
Yes same problem here, we cannot mock a final class with Mockito. To be accurate, Mockito cannot mock/spy following:
final classes
anonymous classes
primitive types
But using a wrapper class seems to me a big price to pay, so get PowerMockito instead.
I think you need think more in principle. Instead you final class use his interface and mock interface instead.
For this:
public class RainOnTrees{
fun startRain():Observable<Boolean>{
// some code here
}
}
add
interface iRainOnTrees{
public void startRain():Observable<Boolean>
}
and mock you interface:
#Before
fun setUp() {
rainService= Mockito.mock(iRainOnTrees::class.java)
`when`(rainService.startRain()).thenReturn(
just(true).delay(3, TimeUnit.SECONDS)
)
}
Please look at JMockit. It has extensive documentation with a lot of examples. Here you have an example solution of your problem (to simplify I've added constructor to Seasons to inject mocked RainOnTrees instance):
package jmockitexample;
import mockit.Mocked;
import mockit.Verifications;
import mockit.integration.junit4.JMockit;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(JMockit.class)
public class SeasonsTest {
#Test
public void shouldStartRain(#Mocked final RainOnTrees rain) {
Seasons seasons = new Seasons(rain);
seasons.findSeasonAndRain();
new Verifications() {{
rain.startRain();
}};
}
public final class RainOnTrees {
public void startRain() {
// some code here
}
}
public class Seasons {
private final RainOnTrees rain;
public Seasons(RainOnTrees rain) {
this.rain = rain;
}
public void findSeasonAndRain() {
rain.startRain();
}
}
}
Solutions provided by RC and Luigi R. Viggiano together is possibly the best idea.
Although Mockito cannot, by design, mock final classes, the delegation approach is possible. This has its advantages:
You are not forced to change your class to non-final if that is what your API intends in the first place (final classes have their benefits).
You are testing the possibility of a decoration around your API.
In your test case, you deliberately forward the calls to the system under test. Hence, by design, your decoration does not do anything.
Hence you test can also demonstrate that the user can only decorate the API instead of extending it.
On a more subjective note:
I prefer keeping the frameworks to a minimum, which is why JUnit and Mockito are usually sufficient for me. In fact, restricting this way sometimes forces me to refactor for good as well.
If you trying to run unit-test under the test folder, the top solution is fine. Just follow it adding an extension.
But if you want to run it with android related class like context or activity which is under androidtest folder, the answer is for you.
Add these dependencies for run mockito successfully :
testImplementation 'org.mockito:mockito-core:2.24.5'
testImplementation "org.mockito:mockito-inline:2.24.5"
Mocking final classes is not supported for mockito-android as per this GitHub issue. You should use Mockk instead for this.
For both unit test and ui test, you can use Mockk with no problem.
If you need to use Mockito in an instrumented test in Android (i. e. running in an Android device), you cannot use mockito-inline. There is a special mockito-android version which doesn't solve the "final class" problem either. The only solution which seems to work is the Dexmaker library. The only limitation is that it works only in Android P (Android 9, API 28) and higher. It can be imported as follows:
androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito-inline:2.28.1"
Beware that there is also a "dexmaker-mockito" version which doesn't work for final classes either. Make sure you import "dexmaker-mockito-inline".
As others have stated, this won't work out of the box with Mockito. I would suggest using reflection to set the specific fields on the object that is being used by the code under test. If you find yourself doing this a lot, you can wrap this functionality in a library.
As an aside, if you are the one marking classes final, stop doing that. I ran across this question because I am working with an API where everything was marked final to prevent my legitimate need for extension (mocking), and I wish that the developer had not assumed that I would never need to extend the class.
For us, it was because we excluded mockito-inline from koin-test. One gradle module actually needed this and for reason only failed on release builds (debug builds in the IDE worked) :-P
For final class add below to mock and call static or non static.
1- add this in class level
#SuppressStatucInitializationFor(value ={class name with package})
2- PowerMockito.mockStatic(classname.class) will mock class
3- then use your when statement to return mock object when calling method of this class.
Enjoy
I was able to overcome this message:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class org.slf4j.impl.Log4jLoggerAdapter
Mockito cannot mock/spy because :
final or anonymous class
from this: log = spy(log);
By using this instead:
log = mock(Logger.class);
Then it works.
I guess that "default" logger adapter is an instance of a final class so I couldn't "spy" it, but I could mock the whole thing. Go figure...
This may mean that you could substitute it for some other "non final" instance if you have that handy, as well. Or a simplified version, etc. FWIW...
I am writing the steps I followed after various unsuccessful attempts to mock final/private classes and their methods in Java 11, which finally worked for me.
Create a file named org.mockito.plugins.MockMaker inside
your test/resources/mockito-extensions folder. Please create
mockito-extensions folder if not present already.
Add a single line mock-maker-inline as the content of the above org.mockito.plugins.MockMaker file
Add
#RunWith(PowerMockRunner.class)
#PowerMockIgnore({"javax.management.*", "jdk.internal.reflect.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.*"})
#PrepareForTest(Utility.class)
annotations at the class level.
Setup process in the test class
#Before
public void setup () {
MockitoAnnotations.initMocks(this);
Mockito.mockStatic(ClassToBeMocked.class);
}
Use Mockito.when(..).thenReturn(..) for assertions
In case of multiple test cases, add the below code
#After
public void after() {
Mockito.framework().clearInlineMocks();
}
The mockito version which I am using: 3.9.0
Java version: 11
Didn't try final, but for private, using reflection remove the modifier worked ! have checked further, it doesn't work for final.

#DataJpaTest not loading required classes

I'm attempting to set up some Spring Boot JPA tests using:
package biz.ianw.coindatabase.test;
#RunWith(SpringRunner.class)
#DataJpaTest
public class DbTests {
#Test
public void test1() { ... }
}
I have a service class:
package biz.ianw.coindatabase.database;
//#Service
#Repository
#Transactional(readOnly=false)
public class CoinDbService { ... }
and an application:
package biz.ianw.coindatabase;
#SpringBootApplication
#Slf4j
#Configuration
#EnableEncryptableProperties
public class Main {
#Autowired
CoinDbService dbService;
... }
Starting the test gives the error:
Field dbService in biz.ianw.coindatabase.Main required a bean of type 'biz.ianw.coindatabase.database.CoinDbService' that could not be found.
This is, I assumed, something to do with the type of beans #DataJpaTest loads during startup:
#DataJpaTest can be used if you want to test JPA applications. By
default it will configure an in-memory embedded database, scan for
#Entity classes and configure Spring Data JPA repositories. Regular
#Component beans will not be loaded into the ApplicationContext.
I'm not quite sure why #Service classes should be considered as not required for JPA testing, but I tried to force the matter by annotating it as #Repository instead, but to no avail.
I can manually load the class with #Import(...) but it seems a tad hooky. Is there a better way to tell DataJpaTest what I need for testing?
I am quoting from DataJpaTest documentation where you can find the answer to your question.
Annotation that can be used in combination with
#RunWith(SpringRunner.class) for a typical JPA test. Can be used when
a test focuses only on JPA components.
Using this annotation will disable full auto-configuration and instead
apply only configuration relevant to JPA tests.
By default, tests annotated with #DataJpaTest will use an embedded
in-memory database (replacing any explicit or usually auto-configured
DataSource). The #AutoConfigureTestDatabase annotation can be used to
override these settings.
If you are looking to load your full application configuration, but
use an embedded database, you should consider #SpringBootTest combined
with #AutoConfigureTestDatabase rather than this annotation.

unable to launch spring-data-rest unit test, RepositoryRestResource not available for #Autowire

I'm porting an app across from JDBC / REST to spring-data-rest and my one and only unit test with fails with the error
NoSuchBeanDefinitionException:
No qualifying bean of type 'com.xxx.repository.ForecastRepository' available
The app was retro-fitted with spring-boot just previously, and now I'm trying to put a new layer in place with spring-data-rest on top of spring-data-jpa.
I'm attempting to work out the correct Java-config according to
Custom Test Slice with Spring Boot 1.4
but I had to deviate from the idiomatic approach because
the #WebMvcTest annotation doesn't suppress the security module which causes the test to fail
the #MockMvcAutoConfiguration fails due to missing dependencies unless I specify #SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) (see here)
#WebMvcTest and #SpringBootTest are mutually exclusive since they both specify #BootstrapWith and can't run together
So this is the closest I've got but Spring can't locate my #RepositoryRestResource repository:
Repository
#RepositoryRestResource(collectionResourceRel = "forecasts", path = "forecasts")
public interface ForecastRepository extends CrudRepository<ForecastExEncoded,
Long> {
JUnit Test
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK,
classes = {TestRestConfiguration.class})
public class ForecastRestTests {
#Autowired
private MockMvc mockMvc;
#Autowired
private ForecastRepository forecastRepository;
#Before
public void deleteAllBeforeTests() throws Exception {
forecastRepository.deleteAll();
}
#Test
public void shouldReturnRepositoryIndex() throws Exception {
mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
jsonPath("$._links.forecasts").exists());
}
}
Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
RepositoryRestMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class,
MockMvcAutoConfiguration.class,
MockMvcSecurityAutoConfiguration.class
})
#Import({PropertySpringConfig.class})
public class TestRestConfiguration {}
Also tried...
I tried to configure the unit test with just #WebMvcTest and this #ComponentScan below from How to exclude AutoConfiguration from Spring Boot), in an attempt to simplify it all, however the excludeFilters had no effect.
#ComponentScan(
basePackages="com.xxx",
excludeFilters = {
#ComponentScan.Filter(type = ASSIGNABLE_TYPE,
value = {
SpringBootWebApplication.class,
JpaDataConfiguration.class,
SecurityConfig.class
})
})
I've set Spring's logging to trace because all I can do at this point is try to find clues as to what is happening from log output. So far though without any luck.
I can see in the logging that RepositoryRestConfiguration is loading, but obviously it isn't fed with the right info and I am unable to work out how that is done, after googling and pouring over the Spring docs and API. I think I must have read every relevant question here on SO .
Update 2016-11-16 10:00
One thing I see in the logs which concerns me is this:
Performing dependency injection for test context [DefaultTestContext#2b4a2ec7 [snip...]
classes = '{class com.xxx.TestRestConfiguration,
class com.xxx.TestRestConfiguration}',
i.e. the context lists the configuration class twice. I specified the config class (once only) on the #SpringBootTest#classes annotation. But if I leave off the #classes from the annotation, Spring Boot finds and pulls in all the config via the #SpringBootApplication class.
So is that a hint that I am specifying the configuration in the wrong place? How else would I do it?
After way too much time, I settled on this approach.
Custom Test Slice with Spring Boot 1.4 looked promising but I couldn't get anywhere with it.
While going over and over
Accessing JPA Data with REST
I realised I had to include the JPA setup because spring-data-rest is using them directly - no chance to mock them or run unit tests without an embedded database.
At least not as far as I understand it. Maybe it is possible to mock them and have spring-data-rest run on the mocks against test data, but I think spring-data-rest and spring-data are probably too tightly coupled.
So integration testing it must be.
In the Spring source code provided with the articles above
gs-accessing-data-rest/ApplicationTests.java
the logging shows Spring Boot pulling in the whole configuration for the application context.
So that my SpringBootApplication class is avoided and the security module isn't loaded up, I set up my tests like this:
#RunWith(SpringRunner.class)
#SpringBootTest
#ContextConfiguration(classes = {
JpaDataConfiguration.class,
TestJpaConfiguration.class,
TestRestConfiguration.class,
PropertySpringConfig.class})
public class ForecastRestTests {
#SuppressWarnings("SpringJavaAutowiringInspection")
#Autowired
private MockMvc mockMvc;
#Autowired
private ForecastRepository forecastRepository;
#Before
public void deleteAllBeforeTests() throws Exception {
forecastRepository.deleteAll();
}
#Test
public void shouldReturnRepositoryIndex() throws Exception {
mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
jsonPath("$._links.forecasts").exists());
}
}
with these configuration classes:
#Configuration
#EnableJpaRepositories(basePackages = {"com.bp.gis.tardis.repository"})
#EntityScan(basePackages = {"com.bp.gis.tardis.type"})
public class JpaDataConfiguration {
and
#Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestJpaConfiguration {}
and
#Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
RepositoryRestMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class,
MockMvcAutoConfiguration.class,
MockMvcSecurityAutoConfiguration.class
})
public class TestRestConfiguration {}
so the TL;DR summary is: use #ContextConfiguration to specify the configuration files that specify #OverrideAutoConfiguration and #ImportAutoConfiguration

When using Ninject for dependeny injection is it best practices to use Ninject in your unit tests or use a mocking framework

I am using ninject to inject dependencies in my production environment. I see two options when it comes to writing unit tests. I can either create concrete classes and inject them using ninject, Or I can use a mocking framework like just mock.
My thought process is to just use both and have the deciding factor be whether or not the TestInterface can be constructed in a reusable way. This way we dont waste time writing the same Mocked method to return an empty list over and over again.
Is there a best practice for this type of thing?
With unit tests on class, it doesn't make a lot of sense to include the DI container in the "system under test" (SUT).
by principle, a class unit test should test the class and the class only
usually you can't "reuse" the bindings in the unit test, you have to create them unit-test specific. Therefore you're only re-testing ninject, but not how you're applying it. Ninject is already tested. So no real benefit for you.
If you do acceptance testing / unit testing on component or application level, then it makes perfectly sense to include Ninject in the SUT.
For a class-level unit test one usually takes a dynamic proxy based mocking framework like MOQ or FakeItEasy.
given an implementation:
public interface IDependency {
void Foo(string bar);
}
public class SomeClass
{
private readonly IDependency dependency;
public SomeClass(IDependency dependency)
{
this.dependency = dependency;
}
public void SomeMethod(string arg)
{
this.dependency.Foo(arg);
}
}
a test would look like (xUnit flavor):
public class SomeClassTest
{
private readonly Mock<IDependency> dependency;
private SomeClass testee;
public SomeClassTest()
{
this.dependency = new Mock<IDependency>();
this.testee = new SomeClass(this.dependency.Object);
}
[Fact]
public void SomeMethod_MustPassArgumentToFoo()
{
const string expectedArgument = "AnyArgument;
this.testee.SomeMethod(expectedArgument);
this.dependency.Verify(x => x.Foo(expectedArgument));
}
}
JustMock has NInject built into it plus a mocking container based on it.
Injecting mocks of dependencies is done automatically when you fetch the instance for the first time:
var container = new MockingContainer<ClassUnderTest>();
var testee = container.Instance;
Plus, you can use NInject's syntax for fine-grained control of the injection behavior, as well as JustMock's syntax for configuring mock behavior.

#Autowired, #Component and testing

How would you go about integration testing a spring application that is annotation-configured and component-scanned and does not have an XML configuration at all? I'm hitting a wall with the need to replace production components with testing components without actually resorting to xml configuration or reflection injections to all the #autowired parts.
Example:
interface A {...}
#Component
class AImpl implements A {
...
}
interface B {...}
#Component
class BImpl implements B {
#Autowired A a;
...
}
interface C {...}
class CImpl implements C {
#Autowired B b;
...
}
then in my test I want to use ATestImpl, but I only have access to C (integration testing C).
How would you go about doing that?
Take advantage of #Primary annotation:
#Service
#Primary
public class TestA implements A {
//...
}
If there is more than one bean implementing A, Spring will prefer the one annotated with #Primary. If you place TestA class in /src/test/java, it will only be picked up during test execution, on normal context startup Spring won't see TestA and use only avaialble AImpl.
Use a dedicated spring context XML file where you override AImpl with an instance of ATestImpl. Of course, it uses XML, but I don't see any other solution (other than repackaging the application with your ATestImpl annotated class instead of the AImpl one)
The new Bean Profile features in Spring 3.1 address the need to swap injected components for testing by defining profiles e.g. test, production etc.
The link to the blog post is here. The Spring team have today released the second milestone release of Spring 3.1.
You can use a special component scan for your test, that exclude the "normal" class and add the test class.
If you have several different test classes, then they should not have a #Component Annotation (or #Service, ...). Instead they should be loaded by an XML Bean declaration. So you can have different XML files for different setups.
<context:component-scan base-package="com.queomedia.sgcrm.base">
<context:exclude-filter expression="com\.example\.AImpl" type="regex"/>
</context:component-scan>
<bean class="com.example.ATestImpl"/>
Using Spring annotation config classes, code the #Bean methods to interfaces. The prod config can perform a componentscan on the high-level package(s) to load the prod objects and the test configs can individually specify beans to return the test versions of your objects. This works very well for component testing where faking service calls and DAO objects is necessary.