Mockito test with ArgumentCaptor failing from time to time - mockito

I am using Java 17, Spring Boot 2.7.5 (spring-boot-starter-test is introducing JUnit Jupiter and Mockito to my project). Full project code (WIP) is here: https://github.com/Tonypsilon/bmm.backend
I have a method that I want to test:
public void verifyUserIsClubAdminOfAnyClub(#NonNull String username, #NonNull Set<Long> clubIds) {
if (clubIds.stream()
.map(clubAdminService::getAdminsOfClub)
.flatMap(Set::stream)
.noneMatch(username::equals)) {
throw new AccessDeniedException("...");
}
}
The method getAdminsOfClub returns a Set of Strings. Here is my test for the success case:
#Test
void testVerifyUserIsClubAdminOfAnyClubSuccess() {
String username = "username";
Set<Long> clubIds = Set.of(1L, 2L);
when(clubAdminService.getAdminsOfClub(1L)).thenReturn(Set.of("some user", "another user"));
when(clubAdminService.getAdminsOfClub(2L)).thenReturn(Set.of("username", "some user"));
ArgumentCaptor<Long> clubIdArgumentCaptor = ArgumentCaptor.forClass(Long.class);
authorizationService.verifyUserIsClubAdminOfAnyClub(username, clubIds);
verify(clubAdminService, times(2)).getAdminsOfClub(clubIdArgumentCaptor.capture());
assertThat(clubIdArgumentCaptor.getAllValues()).containsExactlyInAnyOrder(1L, 2L);
}
The test is passing about 80% of the times I run it with Eclipse. Until now, it passed of the runs in Intellij IDEA. Note that Eclipse somehow needs about half as much time for test execution.
When it fails, this is the stack trace:
org.mockito.exceptions.verification.TooFewActualInvocations:
clubAdminService.getAdminsOfClub(
<Capturing argument>
);
Wanted 2 times:
-> at de.tonypsilon.bmm.backend.security.rnr.service.AuthorizationServiceTest.testVerifyUserIsClubAdminOfAnyClubSuccess(AuthorizationServiceTest.java:39)
But was 1 time:
-> at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
at de.tonypsilon.bmm.backend.security.rnr.service.AuthorizationServiceTest.testVerifyUserIsClubAdminOfAnyClubSuccess(AuthorizationServiceTest.java:39)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:214)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:210)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:135)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:66)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
I thought it might be related to the test cases in general executing very fast (~0,01s), so maybe something is happening there in parallel where something finishes before it should. But I am not sure about the internals and I wouldn't expect such a behaviour.
So my next thought would be that I am using ArgumentCaptor in the wrong way, as I am not very experienced with it. I tried to read up about it but couldn't find information helping me with my specific case. Is anyone able to help me? Thanks in advance!

The issue is likely related to the input set. Since HashSet has no deterministic order, it will either arrive at the subject method as [1, 2] or [2, 1].
That verification step will fail if it arrives as [2, 1] because streams are optimized to fail fast, and since it finds "username" in the first iteration it won't make the second attempt.
The above should be easy to verify by adding a System.out.println(clubIds) at the start of the verifyUserIsClubAdminOfAnyClub method and checking that the test fails every time it prints [2, 1].
public void verifyUserIsClubAdminOfAnyClub(#NonNull String username, #NonNull Set<Long> clubIds) {
System.out.println(clubIds);
// ...
}
If that's the case, it's also likely that if you replace the HashSet with a TreeSet, the test will pass 100% of the time (not implying this should be the solution, but more like a proof of concept).
// Example
Set<Long> clubIds = new TreeSet<>(List.of(1L, 2L));

This might not be an exact answer to your question, but I would suggest to split up this test into multiple smaller ones:
test that the returns of getAdminsOfClub works for no occurence of the admin
test that the returns of getAdminsOfClub works for one occurence of the admin
test that the returns of getAdminsOfClub works for multiple occurences of the admin
test that the getAdminsOfClub method is invoked once for each club
This way you would not have to use the ArgumentCaptorat all:
#Test
void verifyUserIsClubAdminOfAnyClub_no_admin() {
when(clubAdminService.getAdminsOfClub(anyLong()))
.thenReturn(Set.of("some user", "another user"));
assertThrows(
AccessDeniedException.class,
()->authorizationService.verifyUserIsClubAdminOfAnyClub("userName", Set.of(1L)),
"..."
);
}
#Test
void verifyUserIsClubAdminOfAnyClub_1_admin() {
when(clubAdminService.getAdminsOfClub(anyLong()))
.thenReturn(Set.of("userName", "another user"), Set.of("some user", "another user"));
assertDoesNotThrow(
()->authorizationService.verifyUserIsClubAdminOfAnyClub("userName", Set.of(1L, 47L))
);
}
#Test
void verifyUserIsClubAdminOfAnyClub_2_admins() {
when(clubAdminService.getAdminsOfClub(anyLong()))
.thenReturn(Set.of("userName", "another user"), Set.of("some user", "userName"));
assertDoesNotThrow(
()->authorizationService.verifyUserIsClubAdminOfAnyClub("userName", Set.of(1L, 47L))
);
}
#Test
void verifyUserIsClubAdminOfAnyClub_calls_getAdminsOfClub_for_each_club() {
assertThrows(
AccessDeniedException.class,
()->authorizationService.verifyUserIsClubAdminOfAnyClub("userName", Set.of(1L, 42L)),
"..."
);
verify(clubAdminService).getAdminsOfClub(1L);
verify(clubAdminService).getAdminsOfClub(42L);
}
The third parameter of assertThrows is the expected message. I hope that you have not "..." as message literally.
If the exception message is dynamic I would just not specify the third parameter in the test - only test that if it's crucial for the programs logic (which shouldn't be the case).

Related

How to fix `UnfinishedStubbingException`?

I have the following:
public class EnvWebEndpointExtensionEnvironmentPostProcessorTests {
#Rule
public ExpectedException thrown = ExpectedException.none();
#Rule
public MockitoRule rule = MockitoJUnit.rule();
final EnvWebEndpointExtensionEnvironmentPostProcessor postProcessor = new EnvWebEndpointExtensionEnvironmentPostProcessor();
#Mock
ConfigurableEnvironment environmentMock;
#Mock
MutablePropertySources propertySourcesMock;
#Test
public void shouldAddPropertySource() {
final MutablePropertySources propertySources = new MutablePropertySources();
doReturn(propertySources) // line 40
.when(environmentMock).getPropertySources();
postProcessor.postProcessEnvironment(environmentMock, null);
assertNotNull(propertySources.get("actuators-defaults"));
}
#Test
public void shouldThrowExceptionOnFailingToAddLaptopPropertySource() {
thrown.expect(RuntimeException.class);
final MutablePropertySources propertySourcesReal = new MutablePropertySources();
doReturn(propertySourcesReal)
.when(environmentMock).getPropertySources();
doReturn(true)
.when(environmentMock).acceptsProfiles("laptop");
doReturn(propertySourcesMock)
.when(environmentMock).getPropertySources();
doThrow(IOException.class) // line 61
.when(propertySourcesMock).addBefore("actuators-defaults", any(ResourcePropertySource.class));
postProcessor.postProcessEnvironment(environmentMock, null);
}
}
When the tests are run individually, they pass but when they're both run, shouldAddPropertySource fails with:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at com.netflix.springboot.actuators.EnvWebEndpointExtensionEnvironmentPostProcessorTests.shouldThrowExceptionOnFailingToAddLaptopPropertySource(EnvWebEndpointExtensionEnvironmentPostProcessorTests.java:61)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
at com.netflix.springboot.actuators.EnvWebEndpointExtensionEnvironmentPostProcessorTests.shouldAddPropertySource(EnvWebEndpointExtensionEnvironmentPostProcessorTests.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.mockito.internal.junit.JUnitRule$1.evaluateSafely(JUnitRule.java:52)
at org.mockito.internal.junit.JUnitRule$1.evaluate(JUnitRule.java:43)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Considering the information I've found and the behavior above, Mockito is storing some static state but the level of my understanding isn't deep enough to figure out a fix for the above. What's the right fix and, in addition, the explanation for the fix?
If you use a matcher as an argument of a stubbed method call, all arguments must be matchers. So you need to replace "actuators-defaults" by eq("actuators-defaults").
I'm not sure why that throws that exception, though.
JB Nizet correctly diagnosed the root cause in his answer: When you use matchers for one argument, you have to use matchers for all arguments.
My hunch is that Mockito is correctly throwing InvalidUseOfMatchersException, which descends from RuntimeException, so your test erroneously passes without exercising your system-under-test. This is an important reason not to catch RuntimeException indiscriminately, especially at the top of a test method. This may also be a reason to use assertThrows or a try { methodUnderTest(); fail(); } catch (YourSpecificException expected) {} idiom.
If that's the case, you're seeing that specific exception because your test runner is calling your tests in shouldThrow, shouldAdd order in the same VM and Mockito keeps its matcher state in a static ThreadLocal that may survive between tests. If that theory is correct, then the InvalidUseOfMatchersException happens before Mockito can store the expectation from line 61, leaving the stubbing on line 61 technically unfinished. Because Mockito doesn't know when one test ends and another begins, it can't reset its state, so Mockito can only detect this case the next time you interact with Mockito (on line 40).
You could improve your experience by calling Mockito.validateMockitoUsage() in an #After method (or by using MockitoRule or MockitoJUnitRunner).

A URI scheme name 'pack' already has a registered custom parser

I am newborn to NUNIT test,facing error as 'A URI scheme name 'pack' already has a registered custom parser'.
[SetUp]
public void OnTestInitialize()
{
UriParser.Register(new GenericUriParser(
GenericUriParserOptions.GenericAuthority), "pack", -1);
EncodeDecode = new EncodeDecodeSeNoSensorModes();
}
[TestCase(1,1,SSTAvail.no,3)]
[TestCase(0, 0, SSTAvail.no, 3)]
[TestCase(0, 1, SSTAvail.no, 0)]
[TestCase(0, 2, SSTAvail.no, 0)]
public void DecodeModeTest(int input1,int input2,SSTAvail Input3,int ExpectedResult)
{
int OutputResult;
//act
OutputResult = EncodeDecode.DecodeMode(input1,input2,Input3);
// assert
NUnit.Framework.Assert.AreEqual(OutputResult, ExpectedResult);
}
If I run one test I am not facing issue. If run all test ended up this error
Added condition check forwhether the parser for a scheme is registered, only once.
if (!UriParser.IsKnownScheme("pack"))
UriParser.Register(new GenericUriParser(GenericUriParserOptions.GenericAuthority), "pack", -1);
Well presumably OnTestInitialize is currently being called once per test, but you want UriParser.Register to be called once in total. That's the sort of thing that makes sense to do in a static initializer, which is guaranteed to be run exactly once per AppDomain.
On the other hand, if your EncodeDecodeSeNoSensorModes class is meant to be dealing with the pack URI scheme, perhaps that's the class that should have the static initializer... it's not really clear what your code is doing.

Testng SoftAssert always returns null

I'm using a softassert in testNG from org.testng.asserts.SoftAssert
I'm testing something very basic - the title - just to see if I can get the soft assert to work and to put feedback in the report if it fails. Problem is, in either case where the assertion should pass or fail, it just always returns null.
#Test
void doTest()
{
driver.get("URL")
System.out.println(driver.getTitle())
l_assert.assertEquals(driver.getTitle(), "String")
l_assert.assertAll()
}
This always returns null
Probably the problem is that you didn't initialize it. You have to have this somewhere:
l_assert = new SoftAssert();
Try to use next example:
l_assert.assertEquals(driver.getTitle(), "String", "Error Message Should Be Here");

NUnit TestCaseSource modification

I have some code that looks like this
[Test, TestCaseSource("NspecRunner")]
public void TextContext (example thing)
{
//does testing like things using thing
while( othread.threadState == running && currentTestCount == StaticList.count)
Thread.Sleep(1000)
}
public List<example> NspecRunner
{
ClassName x = new ClassName
Thread othread = new Thread(new ThreadStart(() => x.function_that_adds_to_StaticList()));
return ClassName.StaticList;
}
However Nunit doesn't ever look at the StaticList that is being returned after the initial look. Do you know of any way to make the TestCaseScenario reevaluate so that it will create a new test as the other thread adds new stuff to that static class. I'm totally open to other frameworks. Or if you know where in the Nunit project I can find a way to modify the way that TestCaseSource works, that would be lovely.
edit:
I'm trying to create a test for each item inside of ClassName.StaticList. I don't know how many are going to be in the list, but I would like each test to start immediately after the item is added to the StaticList by the other thread. Is that possible?

MbUnit Icarus self-destructs on this test

I'm trying to test a multi-threaded IO class using MbUnit. My goal is to have the test fixture constructor execute 3 times, once for each row on the class. Then, for each instance, execute the tests multiple times on parallell threads.
However, Icarus blows up with an 'index out of range' on TaskRunner. I can't get the full stack, it spawns message boxes too fast.
What am I doing wrong, or is this a bug in MbUnit/Gallio?
using System;
using System.Collections.Generic;
using System.Text;
using Gallio.Framework;
using MbUnit.Framework;
using MbUnit.Framework.ContractVerifiers;
using System.IO;
namespace ImageResizer.Plugins.DiskCache.Tests {
[TestFixture]
[Row(0,50,false)]
[Row(0,50,true)]
[Row(8000,100,true)]
public class CustomDiskCacheTest {
public CustomDiskCacheTest(int subfolders, int totalFiles, bool hashModifiedDate) {
char c = System.IO.Path.DirectorySeparatorChar;
string folder = System.IO.Path.GetTempPath().TrimEnd(c) + c + System.IO.Path.GetRandomFileName();
cache = new CustomDiskCache(folder,subfolders,hashModifiedDate);
this.quantity = totalFiles;
for (int i = 0; i < quantity;i++){
cache.GetCachedFile(i.ToString(),"test",delegate(Stream s){
s.WriteByte(32); //Just one space
},defaultDate, 10);
}
}
int quantity;
CustomDiskCache cache = null;
DateTime defaultDate = new DateTime(2011, 1, 1);
[ThreadedRepeat(150)]
[Test(Order=1)]
public void TestAccess() {
CacheResult r =
cache.GetCachedFile(new Random().Next(0, quantity).ToString(), "test",
delegate(Stream s) { Assert.Fail("No files have been modified, this should not execute"); }, defaultDate, 100);
Assert.IsTrue(System.IO.File.Exists(r.PhysicalPath));
Assert.IsTrue(r.Result == CacheQueryResult.Hit);
}
volatile int seed = 0;
[Test (Order=2)]
[ThreadedRepeat(20)]
public void TestUpdate() {
//try to get a unique date time value
DateTime newTime = DateTime.UtcNow.AddDays(seed++);
CacheResult r =
cache.GetCachedFile(new Random().Next(0, quantity).ToString(), "test",
delegate(Stream s) {
s.WriteByte(32); //Just one space
}, newTime, 100);
Assert.AreEqual<DateTime>(newTime, System.IO.File.GetLastWriteTimeUtc(r.PhysicalPath));
Assert.IsTrue(r.Result == CacheQueryResult.Miss);
}
[Test(Order=3)]
public void TestClear() {
System.IO.Directory.Delete(cache.PhysicalCachePath, true);
}
}
}
I wont answer direct question about bug but I think following steps will help find the error and not get lost in popping message boxes
decrease numbers of totalfiles ,
subfolders to much lower values to
see if error persists in 2 or even 1
file counts
your tests code isn't
super easy, as it should be,
write tests for tests
so you know they are running
correct, maybe those random nexts
are the problem, maybe something
else, tests should be easy.
figure out what test breaks the
system, your code contains 3 tests,
and constructor, comment two other
tests and see which one produces
error
your threaded repeat 150
looks pretty sick, maybe try smaller
number like 2 or 3 if error is basic
even 2 threads might break, if you
run 150 threads I can understand
your trouble with message boxes
add logging and try catch - catch
that index exception and log your
class state carefully, after
inspecting it I think youll see
problem much more clearly.
Right now you cant figure out the problem I think, you got too many variables , not to mention you didnt provide code for your Cache class which might contain some simple error that is causing it, before MBunit features even begin to show up.

Resources