I have UI automation tests. Tests involve three entities -
Data object class - data to be filled in forms. Herein each form on a page could be represented by a different data object.
Helper class - which fills in data in a form on page
Test class - which uses data object and helper class to perform test.
Following is the cut down version of test -
public class ParallelDataObject {
HelperClass helperClass = new HelperClass();
Data data;
#BeforeMethod
public void setTestData() {
data = new Data();
helperClass.setData(data);
}
#Test
public void passM1() {
helperClass.verifyFlag();
}
#Test
public void failM2() {
data.setFlag(false);
helperClass.setData(data);
helperClass.verifyFlag();
}
#Test
public void passM3() {
helperClass.verifyFlag();
}
#Test
public void failM4() {
data.setFlag(false);
helperClass.setData(data);
helperClass.verifyFlag();
}
}
class HelperClass {
Data data;
public void setData(Data data) {
synchronized (data) {
this.data = data;
}
}
public void verifyFlag() {
synchronized (data) {
assert data.getFlag();
}
}
}
class Data {
private boolean flag;
public Data() {
flag = true;
}
public Data setFlag(boolean flag) {
synchronized (this) {
this.flag = flag;
return this;
}
}
public boolean getFlag() {
synchronized (this) {
return flag;
}
}
When executing methods in parallel I encountered weird results as data is not thread safe. Then I incorporated synchronize blocks but yet I encounter weird results.
I am sure I have messed up how synchronization should be used here in. Any insight?
I did one more exercise. I set up another Test class exactly same as first test class. I removed all synchronization from helper and data class. When I run classes in parallel (instead of methods). Test results are as expected. Why don't I run in to concurrency when I execute classes in parallel, even though they user same helper class and data object?
HelperClass and Data are thread-safe.
The problem is that some of your test methods perform several operations. And sequence of the operations in test method is not atomic as long as it not synchronized.
For example during failM4 execution the state of helperClass might be modified by other thread.
I'd recommend you to not use shared state between test methods because synchronization will nullify the advantages of concurrent tests execution.
Consider using ThreadLocal. This way each thread has its own copy of HelperClass. Note that synchronizing separate methods won't give you anything - changes made in one test (in one thread) are visible by other tests
class ParallelDataObject {
private final ThreadLocal<HelperClass> helperClassThreadLocal = new ThreadLocal<HelperClass>() {
#Override
protected HelperClass initialValue() {
return new HelperClass(new Data());
}
};
private HelperClass helperClass() {
return helperClassThreadLocal.get();
}
#Test
public void passM1() {
helperClass().verifyFlag();
}
#Test
public void failM2() {
helperClass().getData().setFlag(false);
helperClass().verifyFlag();
}
}
class HelperClass {
private final Data data;
public HelperClass(Data data) {
this.data = data;
}
public Data getData() {
return data;
}
public void verifyFlag() {
assert data.getFlag();
}
}
class Data {
private boolean flag = true;
public Data setFlag(boolean flag) {
this.flag = flag;
return this;
}
public boolean getFlag() {
return flag;
}
}
Other improvements:
passM3 and failM4 were superfluous
since HelperClass requires an instance of Data to work, it should declare it using constructor dependency
when using:
synchronized(this)
wrapping whole method body, consider using synchronized keyword in method declaration instead (more readable).
synchronization is no longer needed with ThreadLocals
Test statelessness
#gpeche makes a good suggestion that tests should be independent. Unfortunately (why, oh why!?) JUnit reuses the same test case class instance (ParallelDataObject in this case) for all test methods execution. This means that assigning any stateful objects to test case class fields is dangerous and must be avoided.
In this particular case the OP would have to create a new instance of HelperClass in each test method (which, in fact, isn't such a bad idea):
class ParallelDataObject {
#Test
public void passM1() {
final HelperClass helperClass = new HelperClass(new Data());
helperClass.verifyFlag();
}
#Test
public void failM2() {
final Data data = new Data();
data.setFlag(false);
final HelperClass helperClass = new HelperClass(data);
helperClass.verifyFlag();
}
}
Related
Forgive the elementary question, I am learning Java still so need some advice on best practice here. I have a valid scenario where I wish to share the same object between two distinct Test classes using JUnit or TestNG. I understand that tests/test classes should not usually share state but this is a long-running journey.
I understand the JVM executes for both frameworks in this order:
#BeforeClass
Construcor call
#Before
#Test
Given I have an Person class with one field name and one getter & setter for same and I instantiate an instance of it in one Test Class:
public class FirstPersonTest {
private Person firstPerson;
#BeforeClass
private void setup() {
firstPerson = new Person("Dave");
}
#Test
public void testName() {
assertEquals("Dave", firstPerson.getName());
}
}
And a second Test class:
public class SecondPersonTest {
private Person firstPerson;
private static String name;
#BeforeClass
private void setup(){
name = firstPerson.getName(); //null pointer, firstPerson reference no longer exists from FirstPersonTest
}
#Test
public void testName(){
assertEquals("Dave", name);
}
}
What is the optimal way of accessing the firstPerson object in the second class? I don't want to instantiate it a second time because I wish to share state for a journey test.
I want to be able to pass firstPerson instance in the constructor or an annotated setup method, but don't wish to instantiate the SecondPersonTest within the body of FirstPersonTest
You can use a singleton class for this purpose.
public class LocalStorage {
private static volatile LocalStorage instance;
private Map<String, Object> data = new HashMap<>();
private LocalStorage() {
}
public static LocalStorage getInstance() {
if (instance == null) {
synchronized (LocalStorage.class) {
if (instance == null) {
instance = new LocalStorage();
}
}
}
return instance;
}
public static void addData(String key, Object value) {
getInstance().data.put(key, value);
}
public static Object getData(String key) {
return getInstance().data.get(key);
}
public static <T> T getData(String key, Class<T> clazz) {
return clazz.cast(getInstance().data.get(key));
}
}
You can store the whole Person object or only the name field of the Person object.
To store:
Person firstPerson = new Person("Dave");
LocalStorage.addData("Dave", firstPerson);
To get it back:
Person firstPerson = LocalStorage.getData("Dave", Person.class);
I'm doing some unit test but I'm having problems trying to test a class. I have a class with a static builder method which returns the class instance:
public class MessageCaller {
public static MessageCaller builder() {
return new MessageCaller();
}
//Other methods
public String publish() {
//publishing to some Messages
return "something";
}
public MessageCaller withAttribute(String key, String value) {
//Some code
return this;
}
}
public class MessageCallerExtended extends MessageCaller {
private Map<String, String> attributes;
#Override
public MessageCaller withAttribute(String key, String value) {
if (this.attributes == null) {
this.attributes = new HashMap();
}
this.attributes.put(key, value);
return this;
}
//It's not working because it's calling the base class builder and is not possible to be Overriten
//because it's a static method.
public static MessageCallerExtended builder() {
return new MessageCallerExtended();
}
#Override
public String publish() {
return "test";
}
}
This is the method which I would like to test, the problem is that is calling the real publish method taking some time to finalize.
public void sendMessages(#Nonnull String group, #Nonnull String state) {
this.message.builder()
.toTopic(xxxx)
.withAttribute(xxx, xxx)
.withAttribute(xxx, xxx)
.withAttribute(xxx,xxx)
.publish();
}
I'm sending the message object in the constructor of the class.
I've created a Wrapper class to use in the unit test but the problem is that the builder method is static and for that reason is not possible to #Override, if I don't use the #Override tag I'll invoke the real builder method and then the real publish method and it is taking too much time to be processed, causing some problems, because is invoked for several unit test.
With Mockito I having similar issues with the static builder method, in fact it's not possible to mock static methods with Mockito. I'm not allowed to use another library like PowerMock for instance.
Any ideas?
Is it possible to test code that is written in lambda function that is passed inside the method process?
#AllArgsConstructor
public class JsonController {
private final JsonElementProcessingService jsonElementProcessingService;
private final JsonObjectProcessingService jsonObjectProcessingService;
private final JsonArrayProcessingService jsonArrayProcessingService;
public void process(String rawJson) {
jsonElementProcessingService.process(json -> {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}, rawJson);
}
}
Since the lambda is lazy the function is not invoked (Function::apply) when I call JsonController::process so is there any way to check that jsonArrayProcessingService::process is called?
#RunWith(JMockit.class)
public class JsonControllerTest {
#Injectable
private JsonElementProcessingService jsonElementProcessingService;
#Injectable
private JsonObjectProcessingService jsonObjectProcessingService;
#Injectable
private JsonArrayProcessingService jsonArrayProcessingService;
#Tested
private JsonController jsonController;
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
// how check here that jsonArrayProcessingService was invoked?
}
}
Just make it testable (and readable) by converting it to a method:
public void process(String rawJson) {
jsonElementProcessingService.process(this::parse, rawJson);
}
Object parse(String json) {
JsonElement element = new JsonParser().parse(json);
if (element.isJsonArray()) {
return jsonArrayProcessingService.process(element.getAsJsonArray());
} else {
return jsonObjectProcessingService.process(element.getAsJsonObject());
}
}
The relevant guiding principles I personally follow are:
anytime my lambdas require curly brackets, convert them to a method
organise code so that it can be unit tested
You may need to change the return type of the parse method to match whatever your processing services (which you didn’t show) return.
Given its relatively-basic redirection logic, don't you just want to confirm which of the #Injectables got called:
#Test
public void test() {
jsonController.process("[{\"key\":1}]");
new Verifications() {{
jsonArrayProcessingService.process(withInstanceOf(JsonArray.class));
}};
}
I have the following set of classes (along with a failing unit test):
Sprocket:
public class Sprocket {
private int serialNumber;
public Sprocket(int serialNumber) {
this.serialNumber = serialNumber;
}
#Override
public String toString() {
return "sprocket number " + serialNumber;
}
}
SlowSprocketFactory:
public class SlowSprocketFactory {
private final AtomicInteger maxSerialNumber = new AtomicInteger();
public Sprocket createSprocket() {
// clang, click, whistle, pop and other expensive onomatopoeic operations
int serialNumber = maxSerialNumber.incrementAndGet();
return new Sprocket(serialNumber);
}
public int getMaxSerialNumber() {
return maxSerialNumber.get();
}
}
SprocketCache:
public class SprocketCache {
private SlowSprocketFactory sprocketFactory;
private Sprocket sprocket;
public SprocketCache(SlowSprocketFactory sprocketFactory) {
this.sprocketFactory = sprocketFactory;
}
public Sprocket get(Object key) {
if (sprocket == null) {
sprocket = sprocketFactory.createSprocket();
}
return sprocket;
}
}
TestSprocketCache unit test:
public class TestSprocketCache {
private SlowSprocketFactory sprocketFactory = new SlowSprocketFactory();
#Test
public void testCacheReturnsASprocket() {
SprocketCache cache = new SprocketCache(sprocketFactory);
Sprocket sprocket = cache.get("key");
assertNotNull(sprocket);
}
#Test
public void testCacheReturnsSameObjectForSameKey() {
SprocketCache cache = new SprocketCache(sprocketFactory);
Sprocket sprocket1 = cache.get("key");
Sprocket sprocket2 = cache.get("key");
assertEquals("cache should return the same object for the same key", sprocket1, sprocket2);
assertEquals("factory's create method should be called once only", 1, sprocketFactory.getMaxSerialNumber());
}
}
The TestSprocketCache unit test always returns a green bar even if I change the following as follows:
Sprocket sprocket1 = cache.get("key");
Sprocket sprocket2 = cache.get("pizza");
Am guessing that I have to use a HashMap.contains(key) inside SprocketCache.get() method but can't seem to figure the logic.
The problem you're having here is that your get(Object) implementation only allows one instance to be created:
public Sprocket get(Object key) {
// Creates object if it doesn't exist yet
if (sprocket == null) {
sprocket = sprocketFactory.createSprocket();
}
return sprocket;
}
This is a typical lazy-loading instantiation singleton pattern. If you invoke get again, an instance will be assigned to sprocket and it will skip the instantiation completely. Note that you don't even use the key parameter at all, so it does not affect anything.
Using a Map would indeed be one way to achieve your objective:
public class SprocketCache {
private SlowSprocketFactory sprocketFactory;
private Map<Object, Sprocket> instances = new HashMap<Object, Sprocket>();
public SprocketCache(SlowSprocketFactory sprocketFactory) {
this.sprocketFactory = sprocketFactory;
}
public Sprocket get(Object key) {
if (!instances.containsKey(key)) {
instances.put(sprocket);
}
return instances.get(key);
}
}
Well, your current Cache implementation does not rely on key, so no wonder it always returns same cached-once value.
If you want to store different values for keys, and assuming you want it to be thread safe, you might end up doing something like this:
public class SprocketCache {
private SlowSprocketFactory sprocketFactory;
private ConcurrentHashMap<Object, Sprocket> cache = new ConcurrentHashMap<?>();
public SprocketCache(SlowSprocketFactory sprocketFactory) {
this.sprocketFactory = sprocketFactory;
}
public Sprocket get(Object key) {
if (!cache.contains(key)) {
// we only wan't acquire lock for cache seed operation rather than for every get
synchronized (key){
// kind of double check locking to make sure no other thread has populated cache while we were waiting for monitor to be released
if (!cache.contains(key)){
cache.putIfAbsent(key, sprocketFactory.createSprocket());
}
}
}
return cache.get(key);
}
}
Couple important side notes:
you'll need CocncurrentHashMap to ensure happens-before paradigm and so other thread will instantly see if cache has been filled;
new cache value creation has to be synchronized so each concurrent
thread won't generate it's own value, overriding previous values during race condition;
synchronization is quite expensive so we only wan't to engage it when needed, and due to same race condition you might get several threads holding monitor at the same time. That is why another check is required AFTER synchronized block to make sure that other thread hasn't already filled that value.
I'm just getting into testing of code. I have done unit tests before but haven't really isolated them. So they were more like integration test (indirectly). I want to give Mockito a try and I have added it to my Intellij IDE.
But I have no idea of how to actually implement mocking at all. There are examples on their website but I just can't wrap my head around the concept of mocking. I know that one uses mocking to isolate the unit testing to ensure that the errors are in the unit itself and not in a dependency.
I wrote the following:
#Test
public void testChangeMemberReturnsTrue() throws Exception {
Member tempMem = new Member();
tempMem.setMemberFirstName("Swagrid");
tempMem.setMemberLastName("McLovin");
tempMem.setMemberID("SM666");
SQLDUMMY.saveMember(tempMem); //Save member to dummy DB.
Member checkMem = new Member();
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) { // Look through all saved members
if (m.equals(tempMem)) { // If match, save to checkMem
checkMem = m;
}
}
assertTrue(tempMem.equals(checkMem)); // Make sure they are really equal.
String newfirstname = "Darius";
String newlastname = "DunkMaster";
assertTrue(memhandling.changeMember(tempMem, newfirstname, newlastname));
}
And here is the actual method:
public boolean changeMember(Member mem, String n1, String n2) {
try {
ArrayList<Member> memArr = SQLDUMMY.getAllMembers();
for (Member m : memArr) {
if (m.equals(mem)) {
m.setMemberFirstName(n1);
m.setMemberLastName(n2);
m.setMemberID(ensureUniqueID(m, m.getMemberID())); //Just a method call to another method in the same class to ensure ID uniqueness.
return true;
}
else {
return false;
}
}
}
catch (Exception e) {
System.out.println("Error4.");
}
return false;
}
I'd like to mock the SQLDUMMY (Which I created just to see if my tests would pass at all, which they do.) The SQLDUMMY class looks like this:
public class SQLDUMMY {
private static ArrayList<Member> memberList = new ArrayList<>();
private static ArrayList<Ship> shipList = new ArrayList<>();
public static ArrayList<Member> getAllMembers() {
return memberList;
}
public static void saveMember(Member m) {
memberList.add(m);
}
public static void deleteMember(Member memIn) {
memberList.remove(memIn);
}
public static void saveShip(Ship newShip) {
shipList.add(newShip);
}
public static ArrayList<Ship> getAllShips() {
return shipList;
}
public static void deleteShip(Ship s) {
shipList.remove(s);
}
}
It basically just consists of getters and add/remove for the ArrayLists that act as a contemporary DB storage.
Summary: How can I mock the SQLDUMMY class (DAO), so it is no longer a dependency for the Unit tests?
You need to read on how Mockito works.
The basic idea is that it extends you class and and overrides all methods and allows you to return what ever you want it too.
Syntax is :
SQLDummy sqlDummy = Mockito.mock(SQLDummy.class);
Mockito.when(sqlDummy.getAllShips()).thenReturn(new ArrayList< Ship >())