diff --git a/src/main/java/org/olat/core/util/cache/CacheWrapper.java b/src/main/java/org/olat/core/util/cache/CacheWrapper.java
index db8ef6a985fd6b6526949491d00ceda342f6ea5d..4a3ac8114618bf0d11ff9054a12fc0350f8236d0 100644
--- a/src/main/java/org/olat/core/util/cache/CacheWrapper.java
+++ b/src/main/java/org/olat/core/util/cache/CacheWrapper.java
@@ -27,6 +27,7 @@ package org.olat.core.util.cache;
 
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.Function;
 
 
 /**
@@ -91,6 +92,8 @@ public interface CacheWrapper<U, V> {
 	
 	public V putIfAbsent(U key, V value);
 	
+	public V computeIfAbsent(U key, Function<? super U, ? extends V> mappingFunction);
+	
 	/**
 	 * In the case of distributed cache, the list can be partial and
 	 * you must carefully setup your cache.
diff --git a/src/main/java/org/olat/core/util/cache/infinispan/InfinispanCacheWrapper.java b/src/main/java/org/olat/core/util/cache/infinispan/InfinispanCacheWrapper.java
index 7fd5c87768806cf67d76cfd721ed0a8d7b280191..6dcdc4fe1288084f8cab7ec8039dcb73216af0df 100644
--- a/src/main/java/org/olat/core/util/cache/infinispan/InfinispanCacheWrapper.java
+++ b/src/main/java/org/olat/core/util/cache/infinispan/InfinispanCacheWrapper.java
@@ -28,6 +28,7 @@ package org.olat.core.util.cache.infinispan;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.function.Function;
 
 import org.infinispan.Cache;
 import org.olat.core.logging.OLATRuntimeException;
@@ -108,6 +109,11 @@ public class InfinispanCacheWrapper<U,V> implements CacheWrapper<U,V> {
 		return cache.putIfAbsent(key, value);
 	}
 
+	@Override
+	public V computeIfAbsent(U key, Function<? super U, ? extends V> mappingFunction) {
+		return cache.computeIfAbsent(key, mappingFunction);
+	}
+
 	@Override
 	public Iterator<U> iterateKeys() {
 		return cache.keySet().iterator();
diff --git a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
index 97481cdb8a1870ced395cb013db2c02063b5150b..ccc421389770c4938a4613aee8e4f9671d559234 100644
--- a/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
+++ b/src/main/java/org/olat/ims/qti21/manager/QTI21ServiceImpl.java
@@ -33,6 +33,8 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.transform.Transformer;
@@ -146,11 +148,15 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
 	private QTI21Module qtiModule;
 	@Autowired
 	private CoordinatorManager coordinatorManager;
+	
 
 	private JqtiExtensionManager jqtiExtensionManager;
 	private XsltStylesheetManager xsltStylesheetManager;
 	private InfinispanXsltStylesheetCache xsltStylesheetCache;
-	private CacheWrapper<File,ResolvedAssessmentObject<?>> assessmentTestsAndItemsCache;
+	private CacheWrapper<File,ResolvedAssessmentTest> assessmentTestsCache;
+	private CacheWrapper<File,ResolvedAssessmentItem> assessmentItemsCache;
+	
+	private final ConcurrentMap<String,URI> resourceToTestURI = new ConcurrentHashMap<>();
 	
 	@Autowired
 	public QTI21ServiceImpl(InfinispanXsltStylesheetCache xsltStylesheetCache) {
@@ -171,7 +177,8 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
         
         jqtiExtensionManager.init();
 
-        assessmentTestsAndItemsCache = coordinatorManager.getInstance().getCoordinator().getCacher().getCache("QTIWorks", "assessmentTestsAndItems");
+        assessmentTestsCache = coordinatorManager.getInstance().getCoordinator().getCacher().getCache("QTIWorks", "assessmentTests");
+        assessmentItemsCache = coordinatorManager.getInstance().getCoordinator().getCacher().getCache("QTIWorks", "assessmentItems");
 	}
 
     @Override
@@ -243,44 +250,30 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
 
 	@Override
 	public ResolvedAssessmentTest loadAndResolveAssessmentTest(File resourceDirectory) {
-		ResolvedAssessmentTest result = (ResolvedAssessmentTest)assessmentTestsAndItemsCache.get(resourceDirectory);
-		if(result == null)  {
+        URI assessmentObjectSystemId = createAssessmentObjectUri(resourceDirectory);
+		File resourceFile = new File(assessmentObjectSystemId);
+		return assessmentTestsCache.computeIfAbsent(resourceFile, file -> {
 			QtiXmlReader qtiXmlReader = new QtiXmlReader(jqtiExtensionManager());
 			ResourceLocator fileResourceLocator = new PathResourceLocator(resourceDirectory.toPath());
 			ResourceLocator inputResourceLocator = 
 	        		ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator);
-	        URI assessmentObjectSystemId = createAssessmentObjectUri(resourceDirectory);
 	        AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, inputResourceLocator);
-	        result = assessmentObjectXmlLoader.loadAndResolveAssessmentTest(assessmentObjectSystemId);
-	        
-	        File resourceFile = new File(assessmentObjectSystemId);
-	        ResolvedAssessmentTest cachedResult = (ResolvedAssessmentTest)assessmentTestsAndItemsCache.putIfAbsent(resourceFile, result);
-	        if(cachedResult != null) {
-	        	result = cachedResult;
-	        }
-		}
-        return result;
+	        return assessmentObjectXmlLoader.loadAndResolveAssessmentTest(assessmentObjectSystemId);
+		});
 	}
 	
 	@Override
 	public ResolvedAssessmentItem loadAndResolveAssessmentItem(URI assessmentObjectSystemId, File resourceDirectory) {
 		File resourceFile = new File(assessmentObjectSystemId);
-		ResolvedAssessmentItem result = (ResolvedAssessmentItem)assessmentTestsAndItemsCache.get(resourceFile);
-		if(result == null) {
+		return assessmentItemsCache.computeIfAbsent(resourceFile, (file) -> {
 			QtiXmlReader qtiXmlReader = new QtiXmlReader(jqtiExtensionManager());
 			ResourceLocator fileResourceLocator = new PathResourceLocator(resourceDirectory.toPath());
 			ResourceLocator inputResourceLocator = 
 	        		ImsQTI21Resource.createResolvingResourceLocator(fileResourceLocator);
 			
 	        AssessmentObjectXmlLoader assessmentObjectXmlLoader = new AssessmentObjectXmlLoader(qtiXmlReader, inputResourceLocator);
-	        result = assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId);
-
-	        ResolvedAssessmentItem cachedResult = (ResolvedAssessmentItem)assessmentTestsAndItemsCache.putIfAbsent(resourceFile, result);
-	        if(cachedResult != null) {
-	        	result = cachedResult;
-	        }
-		}
-        return result;
+	       	return assessmentObjectXmlLoader.loadAndResolveAssessmentItem(assessmentObjectSystemId);
+		});
 	}
 	
 	@Override
@@ -304,7 +297,8 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
 		try(FileOutputStream out = new FileOutputStream(resourceFile)) {
 			qtiSerializer().serializeJqtiObject(assessmentObject, out);
 			//TODO qti
-			assessmentTestsAndItemsCache.remove(resourceFile);
+			assessmentTestsCache.remove(resourceFile);
+			assessmentItemsCache.remove(resourceFile);
 			return true;
 		} catch(Exception e) {
 			log.error("", e);
@@ -313,16 +307,19 @@ public class QTI21ServiceImpl implements QTI21Service, InitializingBean, Disposa
 	}
 
 	@Override
-	public URI createAssessmentObjectUri(File resourceDirectory) {
-		File manifestPath = new File(resourceDirectory, "imsmanifest.xml");
-		QTI21ContentPackage	cp = new QTI21ContentPackage(manifestPath.toPath());
-		try {
-			Path testPath = cp.getTest();
-			return testPath.toUri();
-		} catch (IOException e) {
-			log.error("", e);
-		}
-		return null;
+	public URI createAssessmentObjectUri(final File resourceDirectory) {
+		final String key = resourceDirectory.getAbsolutePath();
+		return resourceToTestURI.computeIfAbsent(key, (directoryAbsolutPath) -> {
+			File manifestPath = new File(resourceDirectory, "imsmanifest.xml");
+			QTI21ContentPackage	cp = new QTI21ContentPackage(manifestPath.toPath());
+			try {
+				Path testPath = cp.getTest();
+				return testPath.toUri();
+			} catch (IOException e) {
+				log.error("", e);
+				return null;
+			}
+		});
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java
index 15fa1860c9b519a5a4479cec03c8f6744c7121a3..45b8fea64d01c34fbd9c38ec629d8d26374b9c67 100644
--- a/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java
+++ b/src/main/java/org/olat/ims/qti21/repository/handlers/QTI21AssessmentTestHandler.java
@@ -64,6 +64,7 @@ import org.olat.fileresource.types.ImsQTI21Resource;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.ims.qti21.QTI21Service;
 import org.olat.ims.qti21.model.IdentifierGenerator;
+import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.xml.AssessmentItemFactory;
 import org.olat.ims.qti21.model.xml.AssessmentTestFactory;
 import org.olat.ims.qti21.model.xml.ManifestPackage;
@@ -146,13 +147,13 @@ public class QTI21AssessmentTestHandler extends FileHandler {
         QTI21Service qti21Service = CoreSpringFactory.getImpl(QTI21Service.class);
 
 		//single choice
-		File itemFile = new File(directory, IdentifierGenerator.newAssessmentTestFilename());
+		File itemFile = new File(directory, IdentifierGenerator.newAsString(QTI21QuestionType.sc.getPrefix()));
 		AssessmentItem assessmentItem = AssessmentItemFactory.createSingleChoice();
 		QtiSerializer qtiSerializer = qti21Service.qtiSerializer();
 		ManifestPackage.appendAssessmentItem(itemFile.getName(), manifestType);	
 		
 		//test
-        File testFile = new File(directory, IdentifierGenerator.newAssessmentItemFilename());
+        File testFile = new File(directory, IdentifierGenerator.newAssessmentTestFilename());
 		AssessmentTest assessmentTest = AssessmentTestFactory.createAssessmentTest(displayName);
         ManifestPackage.appendAssessmentTest(testFile.getName(), manifestType);
         
diff --git a/src/main/java/org/olat/upgrade/OLATUpgrade_11_0_0.java b/src/main/java/org/olat/upgrade/OLATUpgrade_11_0_0.java
index 10002985fe28b9baffa36b33fa63f78b39683603..db3e5fa74a8f4df5b2581a7ad626d4929e8a8cf1 100644
--- a/src/main/java/org/olat/upgrade/OLATUpgrade_11_0_0.java
+++ b/src/main/java/org/olat/upgrade/OLATUpgrade_11_0_0.java
@@ -41,6 +41,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
 
 import org.olat.admin.user.imp.TransientIdentity;
 import org.olat.basesecurity.GroupRoles;
@@ -1098,6 +1099,12 @@ public class OLATUpgrade_11_0_0 extends OLATUpgrade {
 			return map.putIfAbsent(key, value);
 		}
 
+		@Override
+		public HashMap<String, Serializable> computeIfAbsent(NewCacheKey key,
+				Function<? super NewCacheKey, ? extends HashMap<String, Serializable>> mappingFunction) {
+			return map.computeIfAbsent(key, mappingFunction);
+		}
+
 		@Override
 		public List<NewCacheKey> getKeys() {
 			return new ArrayList<>(map.keySet());
diff --git a/src/test/java/org/olat/gatling/BigAssessmentTestPackageBuilder.java b/src/test/java/org/olat/gatling/BigAssessmentTestPackageBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..997429c50fd72ef05196b51052668210db1c0140
--- /dev/null
+++ b/src/test/java/org/olat/gatling/BigAssessmentTestPackageBuilder.java
@@ -0,0 +1,140 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.gatling;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.net.URISyntaxException;
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.Date;
+
+import org.junit.Test;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.ims.qti21.model.IdentifierGenerator;
+import org.olat.ims.qti21.model.QTI21QuestionType;
+import org.olat.ims.qti21.model.xml.AssessmentItemFactory;
+import org.olat.ims.qti21.model.xml.AssessmentTestFactory;
+import org.olat.ims.qti21.model.xml.ManifestPackage;
+import org.olat.imscp.xml.manifest.ManifestType;
+
+import uk.ac.ed.ph.jqtiplus.JqtiExtensionManager;
+import uk.ac.ed.ph.jqtiplus.node.content.variable.RubricBlock;
+import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
+import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
+import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
+import uk.ac.ed.ph.jqtiplus.node.test.ItemSessionControl;
+import uk.ac.ed.ph.jqtiplus.node.test.Ordering;
+import uk.ac.ed.ph.jqtiplus.node.test.Selection;
+import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
+import uk.ac.ed.ph.jqtiplus.node.test.View;
+import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer;
+
+/**
+ * 
+ * Initial date: 04.06.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BigAssessmentTestPackageBuilder {
+	
+	private static final SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-HHmmss");
+	private static final OLog log = Tracing.createLoggerFor(BigAssessmentTestPackageBuilder.class);
+	private static final QtiSerializer qtiSerializer = new QtiSerializer(new JqtiExtensionManager());
+	
+	private int numOfSections = 15;
+	private int numOfQuestions = 500;
+	
+	@Test
+	public void createAssessmentTest() throws URISyntaxException {
+		String date = format.format(new Date());
+		File directory = new File("/HotCoffee/qti/" + date + "/");
+		directory.mkdirs();
+		ManifestType manifestType = ManifestPackage.createEmptyManifest();
+		System.out.println(directory);
+        
+
+		//test
+        File testFile = new File(directory, IdentifierGenerator.newAssessmentTestFilename());
+		AssessmentTest assessmentTest = AssessmentTestFactory.createAssessmentTest("Big test " + date);
+        ManifestPackage.appendAssessmentTest(testFile.getName(), manifestType);
+
+		TestPart part = assessmentTest.getTestParts().get(0);
+		part.getAssessmentSections().clear();
+
+		// section
+		for(int i=0; i<numOfSections; i++) {
+			AssessmentSection section = new AssessmentSection(part);
+			section.setFixed(Boolean.TRUE);
+			section.setVisible(Boolean.TRUE);
+			section.setTitle((i+1) + ". Section");
+			section.setIdentifier(IdentifierGenerator.newAsIdentifier("sec"));
+			part.getAssessmentSections().add(section);
+			
+			Ordering ordering = new Ordering(section);
+			ordering.setShuffle(true);
+			section.setOrdering(ordering);
+			
+			Selection selection = new Selection(section);
+			selection.setSelect(4);
+			section.setSelection(selection);
+			
+			ItemSessionControl itemSessionControl = new ItemSessionControl(section);
+			itemSessionControl.setAllowSkipping(Boolean.TRUE);
+			itemSessionControl.setAllowComment(Boolean.FALSE);
+			itemSessionControl.setShowFeedback(Boolean.FALSE);
+			section.setItemSessionControl(itemSessionControl);
+			
+			RubricBlock rubrickBlock = new RubricBlock(section);
+			rubrickBlock.setViews(Collections.singletonList(View.CANDIDATE));
+			section.getRubricBlocks().add(rubrickBlock);
+			
+			for(int j=0; j<numOfQuestions; j++) {
+				//single choice
+				String itemId = IdentifierGenerator.newAsString(QTI21QuestionType.sc.getPrefix());
+				File itemFile = new File(directory, itemId + ".xml");
+				AssessmentItem assessmentItem = AssessmentItemFactory.createSingleChoice();
+				assessmentItem.setTitle((i+1) + "." + (j+1) + ". Question SC");
+				
+				AssessmentTestFactory.appendAssessmentItem(section, itemFile.getName());
+				ManifestPackage.appendAssessmentItem(itemFile.getName(), manifestType);	
+				
+				try(FileOutputStream out = new FileOutputStream(itemFile)) {
+					qtiSerializer.serializeJqtiObject(assessmentItem, out);	
+				} catch(Exception e) {
+					log.error("", e);
+				}
+			}
+		}
+		
+		try(FileOutputStream out = new FileOutputStream(testFile)) {
+			qtiSerializer.serializeJqtiObject(assessmentTest, out);	
+		} catch(Exception e) {
+			log.error("", e);
+		}
+		
+		try(FileOutputStream out = new FileOutputStream(new File(directory, "imsmanifest.xml"))) {
+        	ManifestPackage.write(manifestType, out);
+        } catch(Exception e) {
+        	log.error("", e);
+        }
+	}
+}
\ No newline at end of file