How do I create an object in a Guice Test module that is used as a mock in one test, but requires to be real object in another.
eg.
Consider I have a class called ConfigService. This is injected into another class called UserService using constructor injection. During testing, I use a TestModule which has various classes and their mocks.
TestModule.java:
public class TestModule extends AbstractModule{
#Override
public void configure() {
ConfigService configService = Mockito.mock(ConfigService.class);
bind(ConfigService.class).toInstance(configService);
UserService userService = new UserService(configService);
bind(UserService.class).toInstance(userService);
}
}
In UserServiceTest, I create an injector and use the instances from this TestModule.
Injector injector = Guice.createInjector(new TestModule());
userService = injector.getInstance(UserService.class);
configService = injector.getInstance(ConfigService.class);
This works fine, the place where I face a problem now is when I need to test ConfigService.class.
If I want to use the same TestModule for the ConfigServiceTest, how do I now change the mock object of ConfigService I created earlier to an actual one for testing. The vice versa is also a problem -> ie. if I have a real object of ConfigService, how do I stub and mock the responses in UserService.class.
Is there a way to achieve this or should I be creating separate test modules for mocks and real objects? Or am I going about the entire process in a wrong way?
You can do that using spy method.
ConfigService realConfigService = new ConfigService();
ConfigService configService = Mockito.spy(realConfigService);
bind(ConfigService.class).toInstance(configService);
What spy does is, whenever you provide stubbing, it will behave as if the object is mocked. Otherwise, it will call the real method of the object.
Please check this answer for more in-depth theory.
Related
I am working on a repository that implements Java Cryptography Architecture and manages keys in a keystore file. I am trying to avoid using external dependencies when testing, therefore using mock tests. However these do not seem to show up when checking for test coverage. Only the tests that are direcrly linked to the source code without using mock seem to be covered.
I would like to mocking in my tests and still achieve test coverage. I have tried using Mockito, Powermock, Powermockito.
Ive also tried using varius mocking methods for the repository like:
private final EncryptionRepositoryImpl encryptionRepositoryMock = mock(EncryptionRepositoryImpl.class);
#SpringBootTest
public class When_managing_keys {
#MockBean
private KeyManagementRepositoryImpl keyManagementRepository;
#Autowired
ApplicationContext context;
#Test
public void when_getting_key_aliases() throws Exception {
List<String> keyAliases = new ArrayList<>();
keyAliases.add(randomUUID().toString());
keyAliases.add(randomUUID().toString());
keyAliases.add(randomUUID().toString());
Mockito.when(keyManagementRepository.getKeyAliases()).thenReturn(keyAliases);
KeyManagementRepositoryImpl repoFromContext = context.getBean(KeyManagementRepositoryImpl.class);
List<String> keyAliasesRes = repoFromContext.getKeyAliases();
assertEquals(keyAliases, keyAliasesRes);
Mockito.verify(keyManagementRepository).getKeyAliases();
}
}
Your test has some mistakes. Let's do a step-by-step below:
You're creating a mock instance (keyManagementRepository) for the type KeyManagementRepositoryImpl
#MockBean
private KeyManagementRepositoryImpl keyManagementRepository;
Then you mock the return whenever the method getKeyAliases() from the keyManagementRepository instance is called;
Mockito.when(keyManagementRepository.getKeyAliases()).thenReturn(keyAliases);
Then you create a new instance (repoFromContext) for the type KeyManagementRepositoryImpl and call the method getKeyAliases from this instance.
KeyManagementRepositoryImpl repoFromContext = context.getBean(KeyManagementRepositoryImpl.class);
List<String> keyAliasesRes = repoFromContext.getKeyAliases();
The above line calls the method from the instance you create (repoFromContext), not from your mocked instance (keyManagementRepository), you see?
I would suggest you #Autowire the service or whatever component you have that makes the call to your KeyManagementRepositoryImpl, inject your mocked repository in this component, and then call the method in this component that calls the getKeyAliases. It will use the return you configured in the Mockito.when call.
I am fairly new to mockito framework. I've been reading upon multiple tutorials in regards to it. One of them I was following is this: https://www.tutorialspoint.com/mockito/mockito_first_application.htm
There is a statement creating a mock of Stock Service.
In this example, we've created a mock of Stock Service to get the dummy price of some stocks
My question is Stock Service is a real service class or mock service class you have to manually stand up for mimicking the real service class. I am a bit confused. Having basic understanding of junit framework. What I had practiced before was if there is a service class Foo then I used actual class that provides all the exposed methods.
public class Foo {
public Foo() { } // construtor
public String returnAddress(String userId) {
// ...
return dataAccesobj.getAddress(userId);
}
}
Calling foo.returnAddress(..) in unit test if I remember right.
The reason I am asking this question is while I was working with mockitoto create a test method for a class, I ran into a unique(?) challenge.
I started with a real service class which depends on its super class constructor to return its instance. The challenge I ran into was this super class constructor initiates DB connection and loading/parsing properties files which I do not need for my test. I was thinking about how to prevent DB connection and loading/reading prop files....
I thought I read from one of mockito tutorials you can isolate testing without having such services. I tried with #Mock and #Spy (not fully understanding well still what they are for..) but it didn't make a difference for output (maybe I misused those annotations).
So what I did was actually creating fake/mock class out of real service class (e.g. Foo) by simply copying it and renamed it as FooMock and put it in src/test/java folder in where unit test class is running from. I kept the mock class exactly same as the real service class except taking out unwanted logic such as db connection or loading/reading prop file for env specific. By doing that I was able to test one of exposed methods that read ldap directory...
I am sorry I got digressed but hope my point is clear at this point. I am not sure the way I handled this situation is right or wrong. I'd appreciate experienced engineers would clarify the way I handled the matter is acceptable in mockito way or not. If not, then plz advise me best way to handle it.
With Mockito,
a mock is an implementation of a wrapper class.
The mock object "wraps" the target of the mock
(the service in your example)
and allows you to define functionality of each method.
There are two mocked functionality options with Mockito;
call the wrapped method and don't call the wrapped method.
I don't know when it would make sense to call the wrapped method,
so I always use don't call the wrapped method.
After you create the mock,
use the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) method to mock functionality.
Edit: some more info.
I will assume that you are using junit v4.
The details of this will differ based on the the junit major release number,
but the actual work will be the same.
Use annotations to define your Mock objects (#Mock),
except in a few special cases.
This will create mocks of non-final classes,
abstract classes,
and interfaces.
Create a "before-test" method using the #Before annotation;
I traditionally name this method preTestSetup,
but the actual name does not matter.
Call MockitoAnnotations.initMocks(this) as the first line of code
in the "before-test" method.
This will find the #Mock annotations and instantiate a mock for each.
Use the ReflectionTestUtils.setField method to inject the mocks into your object (assuming that you don't have setter methods,
which I traditionally don't like).
Define the mocked functionality of each method using the Mockito.doReturn(returnvalue).when(mockObject).method(method parameters) technique.
Here is some example code
(caveat:
this should be fully functional,
but I did not compile it):
public interface MyService
{
String blammy(SomeParameter parameter);
}
public class UsesMyService
{
#Autowired
private MyService myService;
public String kapow(final SomeParameter parameter)
{
return myService.blammy(parameter);
}
}
public class UnitTestUsesMyService
{
private UsesMyService classToTest;
#Mock
private MyService mockMyService;
#Mock
private SomeParameter mockSomeParameter;
#Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
classToTest = new UsesMyService();
doReturn("Blam").when(mockMyService).blammy(mockSomeParameter);
ReflectionTestUtils.setField(
classToTest,
"myService",
mockMyService);
}
#Test
public void kapow_allGood_success()
{
final String actualResult;
actualResult = classToTest.kapow(mockSomeParameter);
assertNotNull(actualResult); // Not strictly necessary.
assertEquals(
"Blam",
actualResult);
}
}
I have a service ISOLanguageService with a method getDefaultLanguage();
I want to mock this service in one class ISOLanguageServiceMock in this way:
public class ISOLanguageServiceMock {
#Mock
private ISOLanguageService isoLanguageService;
public ISOLanguageServiceMock() {
MockitoAnnotations.initMocks(this);
ISOLanguage isoLanguage = new ISOLanguage();
isoLanguage.setLanguageCode("EN");
when(isoLanguageService.getDefaultLanguage()).thenReturn(isoLanguage);
}
Then i have other service UserService that uses this service isoLanguageService in one of its metdhods.
public void doSomtthing() {
return isoLanguageService.getDefaultLanguage()
}
I want to test the UserService but i want in someway to reuse the mock ISOLanguageServiceMock because it's going to be used in many other services.
I want Something like this
#RunWith(PowerMockRunner.class)
public class UserServiceTest {
private ISOLanguageServiceMock languageMock = new ISOLanguageServiceMock();
#InjectMocks
private UserService userService;
public void setUp() {
MockitoAnnotations.init(this)
}
public void testDoSomething() {
userService.doDomething();
}
}
I'd like that the mock for isoLanguageService be injected in the userService, but it's not...
Is there anyway to reuse a mocks ?? Do i have to write in every test class the mock for isoLanguageService ??
You can't reuse mocks this way. You need #Mock instances to be in your test case, and use them there.
Meaning:
#Mock
private ISOLanguageService isoLanguageService;
and specifications for into your UserServiceTest class.
Mockito does not understand (or care) that your ISOLanguageServiceMock class contains something that could be injected into the class under test.
Mockito looks for the mocks you have in your test class, and those get injected, nothing else!
Regarding the re-use aspect:
you could do that by subclassing (having a base class with that #Mock field)
but then, that is bad practice, to a certain degree. Unit tests should be self contained, as much as possible. It is okay when unit tests duplicate code, because you want to be able to look at one file (your test case) to understand what is going on).
Meaning: (in general), code duplication within unit tests isn't that crucial. The goal of unit tests is to enable quick debugging.
Well, some alternatives:
you can of course, not use #InjectMocks. In that case, your production code needs another way for you to inject mocked objects yourself (either setters, or test only constructors).
when you inject manually, you can of course inject whatever mock object you want to, even one that comes from another class
but then: no extra class required, simply have a static method somewhere that returns a (pre-configured) mock.
Here's how we are using Guice in a new application:
public class ObjectFactory {
private static final ObjectFactory instance = new ObjectFactory();
private final Injector injector;
private ObjectFactory() throws RuntimeException {
this.injector = Guice.createInjector(new Module1());
}
public static final ObjectFactory getInstance() {
return instance;
}
public TaskExecutor getTaskExecutor() {
return injector.getInstance(TaskExecutor.class);
}
}
Module1 defines how the TaskExecutor needs to be constructed.
In the code we use ObjectFactory.getInstance().getTaskExecutor() to obtain and the instance of TaskExecutor.
In unit tests we want to be able to replace this with a FakeTaskExecutor essentially we want to get an instance of FakeTaskExecutor when ObjectFactory.getInstance().getTaskExecutor() is called.
I was thinking of implementing a FakeModule which would be used by the injector instead of the Module1.
In Spring, we would just use the #Autowired annotation and then define separate beans for Test and Production code and run our tests with the Spring4JunitRunner; we're trying to do something similar with Guice.
Okay, first things first: You don't appear to be using Guice the way it is intended. Generally speaking, you want to use Guice.createInjector() to start up your entire application, and let it create all the constructor arguments for you without ever calling new.
A typical use case might be something like this:
public class Foo {
private final TaskExecutor executor;
#Inject
public Foo(TaskExecutor executor) {
this.executor = executor;
}
}
This works because the instances of Foo are themselves injected, all the way up the Object Graph. See: Getting started
With dependency injection, objects accept dependencies in their constructors. To construct an object, you first build its dependencies. But to build each dependency, you need its dependencies, and so on. So when you build an object, you really need to build an object graph.
Building object graphs by hand is labour intensive, error prone, and makes testing difficult. Instead, Guice can build the object graph for you. But first, Guice needs to be configured to build the graph exactly as you want it.
So, typically, you don't create a Singleton pattern and put the injector into it, because you should rarely call Guice.createInstance outside of your main class; let the injector do all the work for you.
All that being said, to solve the problem you're actually asking about, you want to use Jukito.
The combined power of JUnit, Guice and Mockito. Plus it sounds like a cool martial art.
Let's go back to the use case I've described above. In Jukito, you would write FooTest like this:
#RunWith(JukitoRunner.class)
public class FooTest {
public static class Module extends JukitoModule {
#Override
protected void configureTest() {
bindMock(TaskExecutor.class).in(TestSingleton.class);
}
}
#Test
public void testSomething(Foo foo, TaskExecutor executor) {
foo.doSomething();
verify(executor, times(2)).someMethod(eq("Hello World"));
}
}
This will verify that your Mock object, generated by Mockito via Jukito has had the method someMethod called on it exactly two times with the String "Hello World" both times.
This is why you don't want to be generating objects with ObjectFactory in the way you describe; Jukito creates the Injector for you in its unit tests, and it would be very difficult to inject a Mock instead and you'd have to write a lot of boilerplate.
I am wondering what is the best practice to test factory behavior code. In my case, the factory creates some dependency instances that will be passed to the constructor of the FooBar instance.
public class FooBarFactory {
private Dependency1 dependency1;
private Dependency2Factory factory;
public FooBarFactory(Dependency1 dependency1, Dependency2Factory factory) {
this.dependency1 = dependency1;
this.factory = factory;
}
public FooBar create() {
return new FooBar(dependency1, factory.create(), new Dependency3());
}
}
The dependencies can be created by some other factories or can be created directly by the factory under test.
To test the factory behavior, what I have to do for now is create some protected getters in FooBar to retrieve the dependencies so I can assert the constructor injection and the dependencies were created correctly.
This is where I am unsure. Adding some getters for the purpose of testing bothers me a little since this it breaks encapsulation. I could also use reflection to retrieve the fields value but I usually consider this bad practice since it is easy to break.
Anyone can provide insights into this problem?
One solution is to mock the FooBar class and verify the constructor invocation through which the instance returned by FooBarFactory#create() was created. Using the JMockit mocking API, such a test would look like:
public class FooBarFactoryTest
{
#Injectable Dependency1 dep1;
#Injectable Dependency2 dep2;
#Cascading #Injectable Dependency2Factory dep2Factory;
#Mocked FooBar mockFooBar;
#Tested factory;
#Test
public void createFooBarWithProperDependencies()
{
assertNotNull(factory.create());
new Verifications() {{ new FooBar(dep1, dep2, (Dependency3) withNotNull()); }};
}
}
I suppose the suggestion that comes to mind would be to in turn inject the FooBarFactory's dependencies as well, so that it takes a Dependency1 and Dependency2Factory as either constructor parameters or as values in setter methods.
As a Unit-Test you should test your unit (class) and just this.
The value created by a factory inside your factory should be tested on its unit-test. For example on your situation, it doesn't make sense to test what dependency2Factory return, because in order to FooBar work, Dependency2Factory should work too (in case it isn't configurable), if it is configurable you can provide your own mock and this would be enough.
And Dependency2Factory should be tested on a separated Unit-Test.
You don't test if the method List.get(int index) works every time you use a list in your implementation right?
How about mocking? Mock every dependency required to run the tested piece of code.
There are a few good mock frameworks like mockito.