I got NPE with the following code. How to initiate the list properly? I want to iterate the list and use the value to create different names
class Comp {
private List<String> testSuite
Comp(List<String> testcase){
this.testSuites = testcase
}
Job start() {
for (String s : testCase) {
Job.newInstance()
.withName("T/TESTS/"+ s)
}
}
def testCase = [
'name1', 'name2'
]
}
Comp.newInstance().start()
I think :
private List<String> testSuite = []
is enough and have no problem with this implementation.
Or you can do it in java way like shown below,
private List<String> testSuite = new ArrayList<>();
Related
I have the a reducer class that I wanted to write test cases:
Reduce class:
public class MyReducer extends Reducer<Text, Text, NullWritable, Text> {
private static final Logger LOG = LogManager.getLogger(MyReducer.class);
public static List<String> l1 = new ArrayList<String>();
String id = null;
private MultipleOutputs<NullWritable, Text> mos;
#Override
public void setup(final Context context) throws IOException, InterruptedException {
mos = new MultipleOutputs<NullWritable, Text>(context);
final Path[] uris = DistributedCache.getLocalCacheFiles(context.getConfiguration());
try {
final BufferedReader readBuffer1 = new BufferedReader(new FileReader(uris[0].toString()));
String line;
while ((line = readBuffer1.readLine()) != null) {
l1.add(line);
}
readBuffer1.close();
} catch (Exception e) {
LOG.error(e);
}
}
public void reduce(final Text key, final Iterable<Text> values, final Context context)
throws IOException, InterruptedException {
final String[] key1 = key.toString().split("-");
final String keyA = key1[10];
final String date = key1[1];
/* Some condition check */
mos.write(NullWritable.get(), new Text(inputEventValue), keyA + "//date=" +
date.substring(0, 4) + "-" + date.substring(4, 6));
}
#Override
public void cleanup(final Context context) throws IOException, InterruptedException {
mos.close();
}
}
Test Case looks like :
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock
private MyReducer.Context mockContext;
MyReducer reducer;
MultipleOutputs<NullWritable, Text> mos;
#Before
public void setUp() {
reducer = new MyReducer();
}
#Test
public void myReducerTest() throws Exception {
MyReducer spy = PowerMockito.spy(new MyReducer());
doNothing().when(spy).setup(mockContext);
mos = new MultipleOutputs<NullWritable, Text>(mockContext);
List<Text> sline = new ArrayList<>() ;
List<String> l1 = new ArrayList<String>();
l1.add(“1234”);
sline.add(new Text(“xyz”));
Whitebox.setInternalState(MyReducer.class,”l1", l1);
Whitebox.setInternalState(MyReducer.class,"mos",mos);
reducer.reduce(new Text(“xyz-20200101-1234),sline,mockContext);
}
#After
public void tearDown() throws Exception {
/*
* this will do the clean up part
*/
verifyNoMoreInteractions(mockContext);
}
When running in Debug mode it goes to the reducer's reduce method and fails with NullPointerException where mos write statement is?
Complete Stack trace:
java.lang.NullPointerException
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.getNamedOutputsList(MultipleOutputs.java:196)
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.<init>(MultipleOutputs.java:324)
at MyTest.myeducerTest
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.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
Mocking mos errors as mos is not a static.
Any suggestion.
Junit - ReduceDriver, withInput, withOutput,testRun doesn't work.
Thanks.
I tried mocking Multiple outputs as suggested:
import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
#Mock
private MyReducer.Context mockContext;
List<String> namedOut = new ArrayList<>();
namedOut.add("NM1");
namedOut.add("NM2");
MultipleOutputs spy = PowerMockito.spy(new MultipleOutputs<>(mockContext));
when(spy, "getNamedOutputsList(mockContext)").thenReturn(namedOut);
But this gives me error : org.powermock.reflect.exceptions.MethodNotFoundException: no method found with name 'getNamedOutputsList(() anyObject())' with parameter types : [] in class org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.
Looks like you did not define what mockContext.getContext() should return for your test, so it returns null and fails.
Based on this sourcecode the methods looks like this (so you might use a different version):
private static List<String> getNamedOutputsList(JobContext job) {
List<String> names = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(
job.getConfiguration().get(MULTIPLE_OUTPUTS, ""), " ");
while (st.hasMoreTokens()) {
names.add(st.nextToken());
}
return names;
}
JobContext seems to refer to your mock Reducer.Context mockContext, so you need to define the appropriate behaviour so that it returns what it is supposed to return.
Note that this call originates from the constructor of MultipleOutputs.
Also take note of the static getCountersEnabled method that is invoked from the constructor and interacts with the context.
Mocking mos errors as mos is not a static.
You could probably use reflections to put a mocked version of mos into your MyReducer class.
Check here for some example on how to mock a private static field.
Edit:
If you try to mock the conig do it like this:
Configuration config = Mockito.mock(Configuration.class);
when(mockContext.getConfiguration()).thenReturn(config);
As far as I see the get that are invoked on the configuration object always provide a default value, so it shouldn't matter if the key/value pair is in there or not.
I am using AEM Mocks to test a custom servlet that uses a configuration, as such:
#Activate
void activate(final Config config) { ... }
I am following the approach described here and here to register and inject the service together with a HashMap, as such:
private static Map<String, Object> myHashMap = new HashMap<>();
...
myHashMap.put("a", "b");
myHashMap.put("c", "d");
...
servlet = context.registerInjectActivateService(new MyServlet(), myHashMap);
However, this approach doesn't work. The config object passed above, inside the activate function, is corrupted. For every key-value pair above, it sets null as the value. So instead of:
a -> b
c -> d
It sets:
a -> null
c -> null
Inside the HashMap. Can anyone please help? Thanks!
P.S. I should add that I am using version 2.3.0 of AEM Mocks since the recent versions cause an issue with an older artifact. For more info on that, see here.
I tested it, and it works with version 2.3.0 too. Could you check the following example? After that, it is probably a maven issue. Then we would need more information.
Here is my test servlet:
#Component(service = Servlet.class,
property = {
SLING_SERVLET_PATHS + "=/bin/servlet/test",
SLING_SERVLET_METHODS + "=GET",
SLING_SERVLET_EXTENSIONS + "=text"
})
#Designate(ocd = TestServlet.Config.class)
public class TestServlet extends SlingSafeMethodsServlet {
#ObjectClassDefinition
public #interface Config {
#AttributeDefinition(
name = "Name",
description = "Name used in the hello world text"
)
String name() default "Alex";
#AttributeDefinition(
name = "Greeting",
description = "Greeting - Morning, to demonstrate the dot-replacement"
)
String greeting_morning() default "Good Morning";
}
private Config config;
#Override
protected void doGet(#Nonnull SlingHttpServletRequest request, #Nonnull SlingHttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().println(this.getGreeting());
}
public String getGreeting() {
return config.greeting_morning() + ", " + config.name();
}
#Activate
void activate(final Config config) {
this.config = config;
}
}
Here is a JUnit 4 test:
public class TestServletTest {
#Rule
public final AemContext context = new AemContext();
#Test
public void testWithoutConfig() {
final TestServlet testServlet = context.registerInjectActivateService(new TestServlet());
assertEquals("Good Morning, Alex", testServlet.getGreeting());
}
#Test
public void testWithConfig() {
final Map<String, Object> properties = new HashMap<>();
properties.put("name", "Berndt");
properties.put("greeting.morning", "Keep sleeping");
final TestServlet testServlet = context.registerInjectActivateService(new TestServlet(), properties);
assertEquals("Keep sleeping, Berndt", testServlet.getGreeting());
}
}
I am using EF Core in a projet to get stored procedure calling. In my context i have the following :
public class MyContext : DbContext
{
public DbQuery<User> UserQuery { get; set; }
public MyContext(DbContextOptions<MyContext> options) : base(options) { }
}
And i call the stored procedure like this :
public virtual async Task<User> GetUserAsync(string name)
{
return await MyContext.Query<User>()
.FromSql($"EXEC [dbo].[GetUser], #Login = {name}")
.FirstOrDefaultAsync();
}
Code is working fine. I need to test this method in unit tests, i'm using InMemoryDatabase to mock my context MyContext like this :
[Fact]
public async Task GetUserAsync_should_return_first_user_with_login_and_password_if_exists()
{
// Arrange
var users = new List<User>
{
new User()
{
Login = "test#outlook.fr",
Password = "pass1",
},
};
var options = new DbContextOptionsBuilder<MyContext>()
.UseInMemoryDatabase(databaseName: "BddName")
.Options;
var context = new MyContext(options);
var loginProvider = A.Fake<LoginProvider>(opts => opts.WithArgumentsForConstructor(() => new LoginProvider(context)));
// Act
// Assert
context.Dispose();
}
And i have no idea how can i set my list into the result of the stored procedure called from DbQuery. I tried to follow this article : https://nodogmablog.bryanhogan.net/2017/11/unit-testing-entity-framework-core-stored-procedures/ but it works for DbSet only and not DbQuery.
I need some advices for this case.
Thanks in advance.
The link in the OP does apply to the DbQuery type as well, as you're mocking the provider. Both DbSet and DbQuery work in the same way in this regard.
See https://stackoverflow.com/a/56940311/2975810 for a previous answer on the topic.
I wrote a few tests in XUnit to test my data access layer. I instantiated my DAL objects & configs the same way I would if I were using it in the actual web application(this is configured to run against a dev environment for testing purposes), however XUnit throws an error:
Message: The following constructor parameters did not have matching fixture data: IConfiguration config, IMediaDataAccess media
I'm a bit new to XUnit, so unsure what the problem is. Normally ASP.NET would inject instances of IConfiguration and IMediaDataAccess for me, but that doesn't seem to be the case here.
My Test class & a sample test case:
public class DataAccessLayerTests
{
public IConfiguration Config { get; set; }
private IMediaDataAccess mediaData;
public IMediaDataAccess MediaData { get => mediaData; set => mediaData = value; }
public DataAccessLayerTests(IConfiguration config, IMediaDataAccess media)
{
this.MediaData = media;
this.Config = config;
}
public void GetAllMediaAsync_MediaListIsReturned()
{
List<Media> testData = mediaData.GetAllMedia().Result;
Assert.IsType<List<Media>>(testData);
}
}
The test(s) all fail due to the following error: Message: The following constructor parameters did not have matching fixture data: IConfiguration config, IMediaDataAccess media
For anyone else having this problem, Alexey's comment is correct. You need to download a mocking framework (like Moq) and use it to mock up the dependencies your code is expecting. For example, below is one of my fixed unit tests:
public void IndexDataModel_ShouldDisplayMedia()
{
var mockLogger = new Mock<ILogger<IndexModel>>();
var mockDataAccess = new Mock<IMediaDataAccess>();
mockDataAccess.Setup(media => media.GetAllMedia()).ReturnsAsync(GetTestMedia());
IndexModel indexController = new IndexModel(mockDataAccess.Object, mockLogger.Object);
var result = indexController.OnGet();
var viewResult = Assert.IsType<PageResult>(result);
var model = Assert.IsAssignableFrom<IEnumerable<Media>>(
indexController.mediaList);
}
The trick is you need to mock up anything that you normally depend on getting injected into your constructor, in my case this was:
var mockLogger = new Mock<ILogger<IndexModel>>();
var mockDataAccess = new Mock<IMediaDataAccess>();
My constructor takes both an ILogger and an IMediaDataAccess, so I needed to mock those. Additionally, the other code is there to provide dummy return values when your mocked dependencies are used by the test. This is done with the .Setup line of code. All this does(I think) is when GetAllMedia() is called, the mock object returns the contents of GetTestMedia() instead of needing to make the actual calls. Just make sure whatever function you write has the same return type as the real function. For reference, this is my GetTestMedia() function:
private List<Media> GetTestMedia()
{
var listMedia = new List<Media>();
Media testMedia = new Media
{
Description = "TestDesc",
Genre = "TestGenre",
Name = "TestName",
Rating = MediaRating.Excellent,
Type = MediaType.Movie,
Id = 1
};
listMedia.Add(testMedia);
Media testMedia2 = new Media
{
Description = "TestDesc2",
Genre = "TestGenre2",
Name = "TestName2",
Rating = MediaRating.Poor,
Type = MediaType.Music,
Id = 2
};
listMedia.Add(testMedia2);
return listMedia;
}
i have a class as follows-
#Repository
public class TableImpl implements Table{
#Autowired
DataSource dataSource;
#Autowired
DataSource dataSource2;
private static List<Object> tableInfo;
public List<Object> getTableInfo() {
return tableInfo;
}
public void setTableInfo(List<Object> tableInfo) {
this.tableInfo = tableInfo;
}
public List<String> fetchColumns(BasicDataSource dataSource){
JdbcTemplate jdbctemplate = new JdbcTemplate(dataSource);
List<Map<String, Object>> columnMap = jdbctemplate.queryForList("show columns from " + tableInfo.get(0).toString());
List<String> columns = new ArrayList<String>();
for (Map<String, Object> column: columnMap)
{
columns.add(column.get("FIELD").toString());
}
return columns;
}}
I wanted to write a test for method fetchColumns here in spock.
This is what I have tried but this is not working--
class TableImplSpec extends spock.lang.Specification{
JdbcTemplate jdbcTemplate=Mock()
DataSource dataSource1=Mock()
def List<Object> tableInfo=[1]
def BasicDataSource dataSourceValue
def BasicDataSource dataSource
def TableImpl obj=new TableImpl(
dataSource: dataSource1
)
def Table obj1=new TableImpl(
dataSource: dataSource1,tableInfo: tableInfo
)
List<Map<String, Object>> recordsList
def "fetch columns"()
{
given:
TableImpl TableImplMock = Mock()
def Table obj2=new TableImpl(
dataSource: dataSource1,tableInfo: tableInfo
)
tableInfo.add(0,"promptpaySched")
tableInfo.add(1,"promptpaySchedID")
tableInfo.add(2,"name,lastname")
tableInfo.add(3,1)
jdbcTemplate.queryForList(_ as String)>> null
when:
obj2.fetchColumns(dataSource)
then:
1*jdbcTemplate.queryForList(_ as String)
}}
the error I am getting is---
IllegalArgumentException: Property 'dataSource' is required. I am totally confused what changes I have to make to my test class.
If you are writing tests for code that is interacting with the database, (i.e. reads data from or stores data into it) you might need to adjust your tests to pass actual dataSource (not mocked one).
Else try to mock at Repository level and use it to return expected objects.