Trying to unit test a simple login feature that uses firebase authentication. Receive an ExceptionInInitializerError when trying to initialise Firebase Authentication within the test class
import com.google.firebase.auth.FirebaseAuth;
#RunWith(MockitoJUnitRunner.class)
public class LoginTest {
#Mock
private LoginView view;
#Mock
private FirebaseAuth firebaseAuth;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
view = mock(LogIn.class);
firebaseAuth = FirebaseAuth.getInstance(); // Error
}
Error message:
java.lang.ExceptionInInitializerError
at com.google.firebase.FirebaseApp.<clinit>(SourceFile:131)
at com.google.firebase.auth.FirebaseAuth.getInstance(Unknown Source)
Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.
You don't want to invoke any part of Firebase during unit testing. The Firebase SDK simply can't be successfully initialized in a unit testing environment running in a JVM. It will be far better if your test mocks a FirebaseAuth instance, and decides what to do when its methods are called. This will involve having it create other mocks of object that it would normally generate. The important thing is to keep Firebase Authentication completely out of your test's code path, so that its not going to generate any errors due to being uninitialized.
Related
The pact-jvm-provider-spring states that for junit5 provider test, it is not required to use the spring library.
However, #PactBroker annotation depends on the system properties. Is there a way to get this working for application properties via the Spring Property Resolver. I tried to create something similar to SpringEnvironmentResolver.kt and used it in the context setup. But that did not work.
#Provider("api-provider-app")
#PactBroker
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
public class PactVerificationTest {
#LocalServerPort
private int port;
#Autowired
private Environment environment;
#TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider.class)
void testTemplate(Pact pact, Interaction interaction, HttpRequest request,
PactVerificationContext context) {
context.setTarget(new HttpTestTarget("localhost", port));
context.setValueResolver(new SpringResolver(environment));
context.verifyInteraction();
}
}
I get the following error
Invalid pact broker host specified ('${pactbroker.host:}'). Please provide a valid host or specify the system property 'pactbroker.host'.
Update
After some more searching found out that the setTarget was not working and that needs to be moved to #BeforeEach method.
#BeforeEach
void setContext(PactVerificationContext context) {
context.setValueResolver(new SpringResolver(environment));
context.setTarget(new HttpTestTarget("localhost", port));
}
The following snippet helped it work with #PactFolder annotation. But the #PactBroker with properties is still not working
There is a new module added to Pact-JVM that extends the JUnit5 support to allow values to be configured in the Spring Context. See https://github.com/DiUS/pact-jvm/tree/master/provider/pact-jvm-provider-junit5-spring. It will be released with the next version of Pact-JVM, which will be 4.0.7.
I'm writing Spring Cloud Contract tests on MVC Controller whith has methods with annotation #PreAuthorize("hasRole('ADMIN')"). What do I need to provide for passing the security of methods?
I need to test security of controller.
Oauth2 security using in project.
I'm junior dev (many things I dont know yet) and it would be greate if you provide me extended answers.
Thanks.
I've created base test class where provided mockMvc in setup() method with annotation #Before.
Base test class has the looking form:
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = AdminController.class)
#ContextConfiguration(classes = {AdminControllerTestConfig.class, TestConfig.class, AdminControllerTestProperty.class})
#ComponentScan(basePackageClasses = AdminController.class)
#TestPropertySource(locations = "/AdminControllerTest.properties")
#AutoConfigureStubRunner(workOffline = true)
public class AdminControllerContractBaseTest {
//code
}
setup method for autogenerated contract tests
#Before
public void setup() {
Admin admin = createAdminUser();
when(adminRepository.findOneByCredentialsId(id)).thenReturn(admin);
RestAssuredMockMvc.standaloneSetup(new AdminController(adminService, credentialsService));
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
tests methods for autogenerated test classes
#Test
public void shouldFindAdminUserById() {
}
#Test
public void shouldNotFindAdminUserById() {
}
#Test
public void userDoesNotLoggedIn() {
}
I know that I'm not providing any deteils about login user for security but I didn't find info about how to do it in my situation with contract tests.
I've tried to set annotation #WithMockUser(roles = "ADMIN") on test methods but it doesn't works.
Maybe I didn't configure enough for passing tests?
By the way I have email and password of user who has access to this API.
In autogenerated tests on method below which according to contract
ResponseOptions response = given().spec(request)
.get("/api/admin/a")
I expected response code 200 after passing tests but actual code is 401
You might want to write an integration test with #SpringBootTest instead of using Spring Cloud Contract to test your security.
Spring Cloud Contract has been created to verify the in- and output of your communication layer and to let you (the producer) know if you're going to break your API so others (the consumers) have a problem using your exposed API.
Please take a look at this sample on how you can setup your Spring Cloud Contract tests without starting the whole application context.
Hope that helps! :)
I want to load Spring initial context inside a AWS lambda handler class. This class is the starting point of my application. I did it in the below way.
#SpringBootApplication
public class LambdaFunctionHandler implements RequestHandler<KinesisEvent, Object> {
#Override
public Object handleRequest(KinesisEvent input, Context context) {
AnnotationConfigApplicationContext appContext = new AnnotationConfigApplicationContext(LambdaFunctionHandler.class);
LambdaFunctionHandler lambdaHandlerBean = appContext.getBean(LambdaFunctionHandler.class);
// some business logic call
return null;
}
}
This is working fine but I'm getting warning on appContext that it should be closed as it is resource leak. this can be fixed by calling appContext.close() but my doubt is whether this way of initializing Spring application context in a non main method is correct ? Most recommended way to do in a main method is like below
SpringApplication app = new SpringApplication(LambdaFunctionHandler.class);
ConfigurableApplicationContext context = app.run(args);
LambdaFunctionHandler lambdaFunctionHandler =
context.getBean(LambdaFunctionHandler.class);
But I don't have the value to replace the args in my case. can anyone suggest the right way of doing this
You can simple class with main method for #SpringBootApplication and
use CommandLineRunner for loading AWS lambda handler. Just implement the run to load the bean
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/CommandLineRunner.html
I have few custom annotations defined on fields of an object like:
public class Person{
#Accountname
String email;
}
Implementation class of #Accountname:
#Autowired ValidationService service;
#Autowired ClientSession clientSession;
#Override
public boolean isValid(final String email, final ConstraintValidatorContext ctx) {
if(!service.isAccountValid(email, clientSession)){
return false;
}
}
I am trying to write junits for these annotations.
#Test
public void validEmailTest()
{
person.setEmail("abc#xyz.com");
Set<ConstraintViolation<Person>> violations = validatorInstance.getValidator().validateProperty(person, "email");
Assert.assertEquals(1, violations.size());
}
But its throwing this error when I execute the test:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.clientSession': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:343)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:34)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.getTarget(CglibAopProxy.java:663)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:614)
at org.hibernate.validator.internal.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:308)
... 45 more
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes(RequestContextHolder.java:131)
at org.springframework.web.context.request.SessionScope.get(SessionScope.java:90)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:329)
... 54 more
Any idea on how to write junits if a validator class has a dependency on services like session etc.?
This should be tested separately (units).
The real logic that validates is in your ValidationService, so test it there, in AccountnameValidator test only the logic that is in there, injecting your dependencies:
#Mock ValidationService service;
#Mock ClientSession clientSession;
#InjectMocks AccountnameValidator av = new AccountnameValidator()
//initialize mocks
//example test
when(service.isAccountValid(email, clientSession)).thenReturn(true);
boolean result = av.isValid(email, ctx);
assertTrue(result);
And finally if you want you can validate presence of the annotation in Person class on email field using reflection.
My app has a ProviderFactory static class that has static utility methods passing back static instances of things like a logger. The rest of my app then can just grab a/the reference to the logger from anywhere without having to pass in the logger (common design practice).
So, another part of my app, the DbCacheProvider, has methods that make calls to the logger so internally it gets a reference to the logger from the factory and then issues calls to it.
My question is that using Moq, I want to verify methods on the logger are being called by the methods within the DbCacheProvider. I can do this using dependency injection when I pass a mock logger into the DbCacheProvider as a parameter, but I'm not passing the logger in (not do I want to). So, how would I verify the DbCacheProvider is making calls to the logger?
If you don't want to pass the logger in through the constructor you'd need to change your ProviderFactory while running unit tests to return your mocked logger.
Anyway there are a couple of reasons it's often suggested to set up dependency injection:
Your tests are more straightforward and don't involve finagling with custom factories
IoC frameworks like Unity, Ninject and Autofac make it easy to create objects when their dependencies are set up this way. If you set up all of your objects this way, the framework will do all the heavy lifting of creating the right objects and passing them in for you. The dependency injection is done automatically and won't be a burden for you.
Old question without an answer, I had a similar problem and solved it like this:
I have the following sample code and need to verify that not only was a method called but was called with a specific value.
public interface ILog
{
void Info(string message);
}
public interface ILogFactory
{
ILog GetLogger();
}
This is the class being tested, where the interface items are being injected:
public class NewAction
{
readonly ILogFactory _logger;
public NewAction(ILogFactory logger)
{
_logger = logger;
}
public void Step1()
{
_logger.GetLogger().Info("Step 1");
}
public void Step2()
{
_logger.GetLogger().Info("Step 2");
}
}
This is obviously a very simplistic view of my actual code, but I needed to verify that Step1 and Step2 are behaving as expected and passed the correct values to the Log, this would mean I also needed to ensure they occurred in the right order. My test:
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
// Arrange
var log = new Mock<ILog>();
var factory = new Mock<ILogFactory>();
factory.Setup(l => l.GetLogger()).Returns(log.Object);
// Act
var action = new NewAction(factory.Object);
action.Step1();
action.Step2();
// Assert
factory.Verify(l => l.GetLogger());
log.Verify(l => l.Info(It.Is<string>(s => s == "Step 1")));
log.Verify(l => l.Info(It.Is<string>(s => s == "Step 2")));
}
}
Hope this helps.