I have a Java/SpringBoot based Kafka Application that consumes from a specific topic. The code is working fine. However, I have to improve the code coverage. There is an abstract class which is not getting covered by the junit
here is the snippet of the abstract class:
public abstract class AbstractEventProcessor<T>{
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractEventProcessor.class)
private KafkaClient kafkaClient;
String topic;
public AbstractEventProcessor(KafkaClient kafkaClient){
this.kafkaClient=kafkaClient;
}
public void abstractEventProcessor(byte[] key, byte[] event, Headers headers){
T message = extractMessage(event);
Store store = extractStore(message);
StoreKey storeKey = null;
private Boolean deadletterFlag = false;
try{
if (Objects.isNull(message) || Object.isNull(store)){
deadletterFlag = true;
return;
}
process(message, store);
} catch (Exception e) {
deadletterFlag=true;
} finally {
if(deadletterFlag){
sendDeadletter(event);
}
}
}
public abstract String getTopicName();
protected abstract void process(T event, Store store);
protected abstract T extractMessage(byte[] messageBytes);
protected abstract Store extractStore(T storeBytes);
private void sendDeadletter(byte[] event){
kafkaClient.publishDeadletter(event);
}
Any help or guidance in unit testing this class using junit / mockito would be great. Thank you
Related
I have this code in main class -
try {
extraPlayer = gson.fromJson(jsonResponse, ExtraPlayer.class);// this returns null
} catch (Exception e) {
e.printStacktrace();
}
Here extraPlayer is coming as null
I have mocked #Mock Gson gsonMock;
Here ExtraPlayer is a static class.
I have written this test code -
#Test
public void test() {
String jsonResponse = "{\"status\":\"waiting\",\"no\":\"12\"}";
when(playerHandlerMock.resetPlayer("someString", "someString", "1",true
)).thenReturn(jsonResponse);
Gson gsonMock = PowerMockito.mock(Gson.class);
ExtraPlayer extraPlayer = new ExtraPlayer();
extraPlayer.setNo("12");
extraPlayer.setStatus("Waiting");
PowerMockito.mockStatic(ResetModemResponse.class); // using this for static class but didn't work.
PowerMockito.when(gsonMock.fromJson(jsonResponse, ExtraPlayer.class)).thenReturn(extraPlayer);
playerMock.performWaiting();
}
ExtraPlayer.java
public static class ExtraPlayer{
String no;
String status;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getNo() {
return code;
}
public void setNo(String no) {
this.no = no;
}
}
I have added these annotations to the test class -
#RunWith(PowerMockRunner.class)
#PrepareForTest(Gson.class)
why extraPlayer is null ? please help/Suggest.
If you were to use the standard #Mock and #InjectMocks annotation with mockito, then yes, the framework would take care of the injection of the mock into the class under test (regardless of the existence of the setters etc.).
Another thing is the playerMock, which i assume is the class under test.
Do not mock the class under test, create a normal instance and then inject the dependencies... the performWaiting method does not seem to accept the response String, so you would have to inject that also somehow (unless you left some parts out):
#Test
public void test() {
// Arrange
String jsonResponse = "{\"status\":\"waiting\",\"no\":\"12\"}";
Gson gsonMock = PowerMockito.mock(Gson.class);
ExtraPlayer extraPlayer = new ExtraPlayer();
extraPlayer.setNo("12");
extraPlayer.setStatus("Waiting");
PowerMockito.when(gsonMock.fromJson(jsonResponse, ExtraPlayer.class)).thenReturn(extraPlayer);
Player player = new Player();
player.setGson(gsonMock);
player.setResponse(jsonResponse);
// Act
player.performWaiting();
// Assert ...
}
I am trying to create a unit test that uses EclipseLink via JPA and I noticed that I needed to inject a DAO into a listener. The code itself works as expected inside a container, but I am having trouble making a unit test for it.
The listener looks like this.
#ApplicationScoped
public class ParticipantListener {
#Inject
private ParticipantDAO dao;
#PrePersist
#PreUpdate
void ensureNoDuplicateSin(final Participant e) throws DuplicateSinException {
final Participant bySin = dao.getBySinAndNotSelf(e.getSin(), e);
if (bySin != null && bySin.getId() != e.getId()) {
throw new DuplicateSinException();
}
}
}
When I run in a unit test dao is not injected.
My test is initialized as follows:
weld = new Weld();
final WeldContainer container = weld.initialize();
vf = Validation.buildDefaultValidatorFactory();
final Map<String, String> props = new HashMap<>();
props.put("javax.persistence.provider", "org.eclipse.persistence.jpa.PersistenceProvider");
emf = Persistence.createEntityManagerFactory("test-pu", props);
em = emf.createEntityManager();
which obviously should not work because there's no relationship between the em/emf and the container
I needed to set the javax.persistence.bean.manager to point to Weld's bean manager. In addition I found that I also
weld = new Weld();
final WeldContainer container = weld.initialize();
final JpaProvider jpaProvider = container.select(JpaProvider.class).get();
final Map<String, Object> props = new HashMap<>();
props.put("javax.persistence.provider", "org.eclipse.persistence.jpa.PersistenceProvider");
props.put("javax.persistence.bean.manager", container.getBeanManager());
emf = Persistence.createEntityManagerFactory("test-pu", props);
em = emf.createEntityManager();
jpaProvider.setEntityManager(em);
In addition I had to change the DAO to not use #PersistenceContext and use #Inject for the entity manager and create a JpaProvider class. During the test it will set the entity manager from the container instance.
#ApplicationScoped
public class JpaProvider {
private EntityManager em;
#Produces
public EntityManager getEntityManager() {
return em;
}
#PersistenceContext
public void setEntityManager(final EntityManager em) {
this.em = em;
}
}
Your solution sounds unwieldy and as far as I understand you needed to change the code under test (which is not-a-good-thing-to-do (TM)).
Rather have a look into arquillian (http://arquillian.org/) and the use with mockito.
Here's a little bit of boilerplate code showing how I usually do this:
#RunWith(Arquillian.class)
public class TestParticipantListener {
// Collection of producer methods and/or static producer fields
// that mock the injected dependencies for the class under test
public static class LocalMocks {
#Produces ParticipantDAO getParticipantDAO() {
ParticipantDAO participantDAO = Mockito.mock(...);
return participantDAO
}
}
#Deployment
public static WebArchive createDeployment() {
PomEquippedResolveStage pom = Maven.resolver().loadPomFromFile("pom.xml");
BeansDescriptor beansXml = Descriptors.create(BeansDescriptor.class)
.addDefaultNamespaces().getOrCreateAlternatives()
.up();
WebArchive jar = ShrinkWrap.create(WebArchive.class)
.addAsLibraries(pom.resolve("org.mockito:mockito-core").withTransitivity().asFile())
.addClass(ParticipantListener.class)
.addClass(ParticipantDAO.class)
.addClass(TestParticipantListener.LocalMocks.class)
// ... other dependencies
.addAsWebInfResource(new StringAsset(beansXml.exportAsString()), "beans.xml");
return jar;
}
#Inject ParticipantListener participantListenerUnderTest;
#Test
public void test() {
... whatever your test is, using the injected instance
}
}
I have a simple Http module:
public class CustomLoggingModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public void BeginRequest(object sender, EventArgs eventArgs)
{
//some code
}
public void EndRequest(object sender, EventArgs eventArgs)
{
//some
}
public void Dispose()
{
}
}
How can I unit test this? Especially how is it possible to mock events? Can anyone give some simple example?
Not sure why you have decided to hardwire the dependencies as new LogService() and new HttpContextWrapper(HttpContext.Current) within the CustomLoggingModule. If want to test whether LogInfo() method is called or not, it becomes lot easier if you can externalize these dependencies so you can inject stubbed/mocked version etc.
Also your question does not state that you are using an IOC container. You can register the HttpModule with the container and provide external dependencies at runtime. Your question also does not state that using an isoloation/mock object framework.
Therefore I will provide you with a solution that you can verify whether LogInfo method is called, using hand written stubs and mocks.
To achieve this, we need to refactor CustomLoggingModule a bit, so it becomes more testable.
System Under Test (SUT)
public class CustomLoggingModule : IHttpModule
{
public ILogService LogService { get; set; }
public Func<ILoggingHttpContextWrapper> LogginHttpContextWrapperDelegate { get; set; }
public void Init(HttpApplication context) {
context.BeginRequest += BeginRequest;
context.EndRequest += EndRequest;
}
public CustomLoggingModule() {
LogginHttpContextWrapperDelegate = () => new LoggingHttpContextWrapper();
}
public void BeginRequest(object sender, EventArgs eventArgs) {
LogService.LogInfo(LogginHttpContextWrapperDelegate().HttpContextWrapper);
}
public void EndRequest(object sender, EventArgs eventArgs) {
//some
}
public void Dispose(){ }
}
As you see above, I have introduced 2 additional properties - ILogService so I can provide a Mocked verion and a delegate Func which allows me to stub the
new HttpContextWrapper(HttpContext.Current);
public interface ILoggingHttpContextWrapper {
HttpContextWrapper HttpContextWrapper { get; }
}
public class LoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public LoggingHttpContextWrapper() {
HttpContextWrapper = new HttpContextWrapper(HttpContext.Current);
}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
And then your real ILogService
public interface ILogService {
void LogInfo(HttpContextWrapper httpContextWrapper);
}
public class LogService : ILogService {
public void LogInfo(HttpContextWrapper httpContextWrapper)
{
//real logger implementation
}
}
Unit Test :
You would create a MockLoggerService, so you can verify the interaction i,e whether the LogInfo() method was called, etc. You also need a stubbed LoggingHttpContextWrapper to provide the fake HttpContextWrapper to the SUT (System Under Test)/ CustomLoggingModule.
public class StubLoggingHttpContextWrapper : ILoggingHttpContextWrapper
{
public StubLoggingHttpContextWrapper(){}
public HttpContextWrapper HttpContextWrapper { get; private set; }
}
public class MockLoggerService : ILogService
{
public bool LogInfoMethodIsCalled = false;
public void LogInfo(HttpContextWrapper httpContextWrapper) {
LogInfoMethodIsCalled = true;
}
}
MockLoggerService is very important. It is not the real logger service, but it is the mocked version. When we do public class MockLoggerService : ILogService this means that we are providing another layer of indirection to the logger service so we can verify the interaction of the behaviour.
You also notice that I have provided a boolean variable to verify whether the LogInfo method is called or not. This allows me to call this method from the SUT, and verify whether the method being called or not.
Now Your Unit Test can be implemented as below.
[TestMethod]
public void CustomLoggingModule_BeginRequest_VerifyLogInfoMethodIsCalled()
{
var sut = new CustomLoggingModule();
var loggerServiceMock = new MockLoggerService();
var loggingHttpContextWrapperStub = new StubLoggingHttpContextWrapper();
sut.LogService = loggerServiceMock;
sut.LogginHttpContextWrapperDelegate = () => loggingHttpContextWrapperStub;
sut.BeginRequest(new object(), new EventArgs());
Assert.IsTrue(loggerServiceMock.LogInfoMethodIsCalled);
}
I had the same issue with my custom http module and decided I won't give up that easily and will do all I can to trigger the BeginRequest event in unit test. I had to actually read through the source code of HttpApplication class and use reflection to invoke the method.
[TestMethod]
public void EventTriggered_DoesNotError()
{
using (var application = new HttpApplication())
{
var module = new CustomLoggingModule();
module.Init(application);
FireHttpApplicationEvent(application, "EventBeginRequest", this, EventArgs.Empty);
}
}
private static void FireHttpApplicationEvent(object onMe, string invokeMe, params object[] args)
{
var objectType = onMe.GetType();
object eventIndex = (object)objectType.GetField(invokeMe, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandlerList events = (EventHandlerList)objectType.GetField("_events", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).GetValue(onMe);
EventHandler handler = (EventHandler)events[eventIndex];
Delegate[] delegates = handler.GetInvocationList();
foreach (Delegate dlg in delegates)
{
dlg.Method.Invoke(dlg.Target, args);
}
}
I am using Fluent NHibernate and trying to do unit testing. Now I have a base test class which looks as follows:
[TestClass]
public abstract class BaseTest<TEntity> where TEntity : IBaseModel
{
private const string testDbFile = "test.db";
private static ISessionFactory sessionFactory;
protected static ISession session;
[TestMethod]
public void configureDB()
{
try
{
if (sessionFactory == null)
{
sessionFactory = Fluently.Configure()
.Database(SQLiteConfiguration.Standard
.UsingFile(testDbFile))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<AdminTest>())
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.Message);
}
}
private static void BuildSchema(Configuration config)
{
new SchemaUpdate(config).Execute(false, true);
}
[TestMethod]
public void sessionCreated()
{
session = sessionFactory.OpenSession();
}
[TestMethod]
public virtual void AddEntity_EntityWasAdded()
{
var entity = BuildEntity();
InsertEntity(entity);
session.Evict(entity);
var reloadedEntity = session.Get<TEntity>(entity.Id);
Assert.IsNotNull(reloadedEntity);
AssertAreEqual(entity, reloadedEntity);
AssertValidId(reloadedEntity);
}
There are also other methods which update and delete an entity. And I have AdminTest class which inherits BaseTest. In AdminTest I have following method:
[TestClass]
public class AdminTest : BaseTest<Admin>
{
[TestMethod]
public void SelectWorks()
{
IList<Admin> admins = session.QueryOver<Admin>().List();
Assert.AreNotEqual(0, admins.Count);
}
}
Here I always have exception, because session is null. Maybe I am wrong in the way of thinking how visual studio performs unit tests (I am newbie in it)?
Now I think like that, visual studio works in the following way
runs test-methods from BaseTest (there it configures database and creates session)
runs selectWorks method. Here I was thinking it should use session from BaseTest
Could you explain what is wrong in my way of thinking? And I want to be able to query from child classes, what is the right way of doing it?
Thanks, any help is appreciated, .
I would suggest using [TestInitialize] and [TestCleanup] in your abstract base class and doing something like the following:
[TestInitialize]
public void TestInitialize()
{
Console.Out.WriteLine("Get a ISession object");
}
[TestCleanup]
public void TestCleanup()
{
Console.Out.WriteLine("Dispose ISession");
}
Then in your child classes continue to do what you are doing:
[TestMethod]
public void DoDbWork()
{
Console.Out.WriteLine("Running a query via nhibernate");
}
You really just want to ensure you have a clean session for each test. The attributes for TestInitialize and TestCleanup will run before and after each unit test. Here is the documentation for those attributes.
To ensure your ISession is in the right state,follow something like this.
I have been given the task to evaluate codeFirst and possible to use for all our future projects.
The evaluation is based on using codeFirst with an existing database.
Wondering if it's possible to mock the repository using codeFirst 4.1.(no fakes)
The idea is to inject a repository into a service and moq the repository.
I have been looking on the net but I have only found an example using fakes.I dont want to use fakes I want to use moq.
I think my problem is in the architecture of the DAL.(I would like to use unitOfWork etc.. by I need to show a working moq example)
Below is my attempt(Failed miserably) due to lack of knowledge on Code first 4.1.
I have also uploaded a solution just in case somebody is in good mood and would like to change it.
http://cid-9db5ae91a2948485.office.live.com/browse.aspx/Public%20Folder?uc=1
I am open to suggestions and total modification to my Dal.Ideally using Unity etc.. but I will worry about later.
Most importantly I need to be able to mock it. Without ability to use MOQ we will bin the project using EF 4.1
Failed attempt
//CodeFirst.Tests Project
[TestClass]
public class StudentTests
{
[TestMethod]
public void Should_be_able_to_verify_that_get_all_has_been_called()
{
//todo redo test once i can make a simple one work
//Arrange
var repository = new Mock<IStudentRepository>();
var expectedStudents = new List<Student>();
repository.Setup(x => x.GetAll()).Returns(expectedStudents);
//act
var studentService = new StudentService(repository.Object);
studentService.GetAll();
//assert
repository.Verify(x => x.GetAll(), Times.AtLeastOnce());
}
}
//CodeFirst.Common Project
public class Student
{
public int StudentId { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
public interface IStudentService
{
IEnumerable<Student> GetAll();
}
//CodeFirst.Service Project
public class StudentService:IStudentService
{
private IStudentRepository _studentRepository;
public StudentService()
{
}
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public IEnumerable<Student> GetAll()
{
//TODO when mocking using moq this will actually call the db as we need a separate class.
using (var ctx = new SchoolContext("SchoolDB"))
{
_studentRepository = new StudentRepository(ctx);
var students = _studentRepository.GetAll().ToList();
return students;
}
}
}
//CodeFirst.Dal Project
public interface IRepository<T> where T : class
{
T GetOne(Expression<Func<T, bool>> predicate);
IEnumerable<T> GetAll();
IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
void Add(T entity);
void Delete(T entity);
T Single(Func<T, bool> predicate);
T First(Func<T, bool> predicate);
}
public class RepositoryBase<T> : IRepository<T> where T : class
{
private readonly IDbSet<T> _dbSet;
public RepositoryBase(DbContext dbContext)
{
_dbSet = dbContext.Set<T>();
if (_dbSet == null) throw new InvalidOperationException("Cannot create dbSet ");
}
protected virtual IDbSet<T> Query
{
get { return _dbSet; }
}
public T GetOne(Expression<Func<T, bool>> predicate)
{
return Query.Where(predicate).FirstOrDefault();
}
public IEnumerable<T> GetAll()
{
return Query.ToArray();
}
public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
{
return Query.Where(predicate).ToArray();
}
public void Add(T entity)
{
_dbSet.Add(entity);
}
public void Delete(T entity)
{
_dbSet.Remove(entity);
}
public T Single(Func<T, bool> predicate)
{
return Query.Where(predicate).SingleOrDefault();
}
public T First(Func<T, bool> predicate)
{
return Query.Where(predicate).FirstOrDefault();
}
}
public class SchoolContext:DbContext
{
public SchoolContext(string connectionString):base(connectionString)
{
Database.SetInitializer<SchoolContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Not sure why I have to do this.Without this when using integration testing
//as opposed to UnitTests it does not work.
modelBuilder.Entity<Student>().ToTable("Student"); }
public DbSet<Student> Students { get; set; }
}
public interface IStudentRepository:IRepository<Student>
{
}
public class StudentRepository : RepositoryBase<Student>, IStudentRepository
{
public StudentRepository(DbContext dbContext)
: base(dbContext)
{
}
public IEnumerable<Student> GetStudents()
{
return GetAll();
}
}
Again feel free to modify or whatever is needed to help me to get something together.
Thanks a lot for your help
When I started with repository and unit of work patterns I used the implementation similar to this (it is for ObjectContext API but converting it to DbContext API is simple). We used that implementation with MOQ and Unity without any problems. By the time implementations of repository and unit of work have evolve as well as the approach of injecting. Later on we found that whole this approach has serious pitfalls but that was alredy discussed in other questions I referenced here (I highly recommend you to go through these links).
It is very surprising that you are evaluating the EFv4.1 with high emphasis on mocking and unit testing and in the same time you defined service method which is not unit-testable (with mocking) at all. The main problem of you service method is that you are not passing repository/context as dependency and because of that you can't mock it. The only way to test your service and don't use the real repository is using some very advanced approach = replacing mocking and MOQ with detouring (for example Moles framework).
First what you must do is replacing your service code with:
public class StudentService : IStudentService
{
private readonly IStudentRepository _studentRepository;
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public IEnumerable<Student> GetAll()
{
return _studentRepository.GetAll().ToList();
}
}
Btw. this is absolutely useless code and example of silly layering which doesn't offer any useful functionality. Just wrapping the call to repository only shows that service is not needed at all as well as unit testing this method is not needed. The main point here is integration test for GetAll method.
Anyway if you want to unit thest such method with MOQ you will do:
[TestClass]
public class StudentsServiveTest
{
private Mock<IRespository<Student>> _repo;
[TestInitialize]
public void Init()
{
_repo = new Mock<IRepository<Student>>();
_repo.Setup(r => r.GetAll()).Returns(() => new Student[]
{
new Student { StudentId = 1, Name = "A", Surname = "B" },
new Student { StudentId = 2, Name = "B", Surname = "C" }
});
}
[TestMethod]
public void ShouldReturnAllStudents()
{
var service = new StudentsService(_repo.Object);
var data = service.GetAll();
_repo.Verify(r => r.GetAll(), Times.Once());
Assert.IsNotNull(data);
Assert.AreEqual(2, data.Count);
}
}
The issue from what I can see is that you are throwing away the mock object and newing up a new instance
_studentRepository = new StudentRepository(ctx);
Perhaps add a method on the interface to add the context object and reuse the same instance that was injected in the constructor.
using (var ctx = new SchoolContext("SchoolDB"))
{
_studentRepository.Context = ctx;
var students = _studentRepository.GetAll().ToList();
return students;
}
}