public class MockComponentWorker extends Object implements ComponentAccessor.Worker
ComponentAccessor
to return mock
instances of components for unit testing.
When a class needs to access another JIRA component, the preferred mechanism to resolve this dependency is by injection in the constructor. Among other things, this makes it easier to see what the dependencies of the class are and also makes it easy for unit tests to provide mocks for those components. However, there are times when dependency injection is impossible or impractical. Examples include:
In these cases, the class can use ComponentAccessor.getComponentOfType(Class)
to resolve the dependency, instead. The drawback is that ComponentAccessor
uses a global, static reference to a ComponentAccessor.Worker
implementation
to accomplish this, and if nothing has initialised that reference, then an
IllegalStateException
is thrown.
Unit tests must be responsible for ensuring that everything they require, directly or indirectly, is arranged during the test's setup, so a unit test that encounters this problem should explicitly initialise the component accessor. In most cases, all they need to do is create and install an instance of this class. For example:
@Before
public void setUp()
{
new
MockComponentWorker()
.init()
;
}
The MockComponentWorker
comes with a few mocks by default, including
implementations for common problem areas, such as the UserKeyService
and
the UserPreferencesManager
, so for many tests this will be enough as-is.
If you need additional mocked components to be resolved in this way, then you can
add them as well. An example might look something like this:
@Before
public void setUp()
{
final ApplicationUser fred = new MockApplicationUser("Fred");
final JiraAuthenticationContext jiraAuthenticationContext = Mockito.mock(JiraAuthenticationContext.class);
Mockito.when(jiraAuthenticationContext.getUser()).thenReturn(fred);
Mockito.when(jiraAuthenticationContext.getUser()).thenReturn(fred.getDirectoryUser());
new
MockComponentWorker()
.addMock
(ConstantsManager.class, new MockStatusConstantsManager())
.addMock
(JiraAuthenticationContext.class, jiraAuthenticationContext)
.init()
;
}
JUnit 4 annotations can also be used to initialise the MockComponentWorker
.
See the
MockComponentContainer
and
MockitoContainer
@Rule
s for examples.
Constructor and Description |
---|
MockComponentWorker() |
Modifier and Type | Method and Description |
---|---|
<T,U extends T> |
addMock(Class<T> componentInterface,
com.atlassian.util.concurrent.LazyReference<U> componentMockRef)
Registers a mock component to be returned by this component worker.
|
<T,U extends T> |
addMock(Class<T> componentInterface,
U componentMock)
Registers a mock component to be returned by this component worker.
|
<T> T |
getComponent(Class<T> componentClass)
Obtains the registered mock of the specified interface type.
|
<T> T |
getComponentOfType(Class<T> componentClass)
Although the
ComponentAccessor specifies different semantics for this method,
in this mock implementation it behaves identically to getComponent(Class) . |
<T> Optional<T> |
getComponentSafely(Class<T> componentClass)
This implementation just wraps the result of
getComponent(Class) with
Optional.ofNullable(Object) . |
MockApplicationProperties |
getMockApplicationProperties() |
MockDatabaseConfigurationService |
getMockDatabaseConfigurationService() |
MockUserKeyService |
getMockUserKeyService() |
MockUserPreferencesManager |
getMockUserPreferences() |
<T> T |
getOSGiComponentInstanceOfType(Class<T> componentClass)
Although the
ComponentAccessor specifies different semantics for this method,
in this mock implementation it behaves identically to getComponent(Class) . |
MockComponentWorker |
init()
Convenience method that just calls
ComponentAccessor .initialiseWorker(this) . |
<T,U extends T> |
registerMock(Class<T> componentInterface,
U componentMock)
Registers a mock component to be returned by this component worker.
|
public <T,U extends T> void registerMock(Class<T> componentInterface, U componentMock)
Since addMock(Class, Object)
is identical but also returns this
for call chaining, it may be more convenient to use.
T
- the componentInterface
U
- the componentMock
's class, which must implement <T>
componentInterface
- the interface that the mock component must implementcomponentMock
- the component that implements the interfaceaddMock(Class, Object)
public <T,U extends T> MockComponentWorker addMock(Class<T> componentInterface, U componentMock)
This method is exactly equivalent to registerMock(Class, Object)
, except that
it also returns this
, making it possible to use it in the convenient call chaining
style illustrated in the documentation for this class.
T
- the componentInterface
U
- the componentMock
's class, which must implement <T>
componentInterface
- the interface that the mock component must implementcomponentMock
- the component that implements the interfacethis
, for conveniencepublic <T,U extends T> MockComponentWorker addMock(Class<T> componentInterface, com.atlassian.util.concurrent.LazyReference<U> componentMockRef)
This method accepts a lazy reference to the implementation in order to allow lazy initialisation on first access.
T
- the componentInterface
U
- the componentMock
's class, which must implement <T>
componentInterface
- the interface that the mock component must implementcomponentMockRef
- the lazy reference to the component that implements the interfacethis
, for conveniencepublic <T> Optional<T> getComponentSafely(Class<T> componentClass)
getComponent(Class)
with
Optional.ofNullable(Object)
.getComponentSafely
in interface ComponentAccessor.Worker
T
- the return type inferred from the specified componentClass
.componentClass
- the interface for which an implementation is desiredOptional
), or Optional.empty()
if no mock
implementation has been provided for it.public <T> T getComponent(Class<T> componentClass)
UserKeyService
) or that the test registered earlier and is now ready to stub.
JIRA itself will also sometimes use this method (or getComponentOfType(Class)
) to
resolve dependencies. Arguably, this method should throw an exception rather than return
null
when a component is requested without a mock provided for it; however, some
unit tests will resolve the component during construction without the test code path
actually needing to use it, so this method just generates a warning message in the log
for this case.
getComponent
in interface ComponentAccessor.Worker
T
- the return type inferred from the specified componentClass
.componentClass
- the interface for which an implementation is desirednull
if no mock implementation has been
provided for it.public <T> T getComponentOfType(Class<T> componentClass)
ComponentAccessor
specifies different semantics for this method,
in this mock implementation it behaves identically to getComponent(Class)
.getComponentOfType
in interface ComponentAccessor.Worker
T
- as for getComponent(Class)
componentClass
- as for getComponent(Class)
getComponent(Class)
public <T> T getOSGiComponentInstanceOfType(Class<T> componentClass)
ComponentAccessor
specifies different semantics for this method,
in this mock implementation it behaves identically to getComponent(Class)
.getOSGiComponentInstanceOfType
in interface ComponentAccessor.Worker
T
- as for getComponent(Class)
componentClass
- as for getComponent(Class)
getComponent(Class)
public MockComponentWorker init()
ComponentAccessor
.initialiseWorker(this)
.
If you are developing a plugin that must support JIRA versions prior to v6.0, then that @Internal
method must be used directly, instead.public MockUserPreferencesManager getMockUserPreferences()
public MockApplicationProperties getMockApplicationProperties()
public MockUserKeyService getMockUserKeyService()
public MockDatabaseConfigurationService getMockDatabaseConfigurationService()
Copyright © 2002-2015 Atlassian. All Rights Reserved.