We have a lot CanExecute tests for a various commands in our project. All tests passed properly when we use Visual Studio testing or AxoCover.
We tried to add some previous object initialization, before executing 'CanExecute' and sometimes it worked (or we thought that).
testedViewModel.Object.InEditMode = inEditMode;
I have a test:
[TestCase(true, true, TestName = "Command_InEditMode_CanExecute")]
[TestCase(false, false, TestName = "Command_NotInEditMode_CannotExecute")]
public void CommandCanExecute(bool inEditMode, bool expectedResult)
{
var testedViewModel =
new Mock<SomeViewModel>(inEditMode)
{
CallBase = true
};
testedViewModel.Setup(x => x.InEditMode).Returns(inEditMode);
Assert.AreEqual(expectedResult, testedViewModel.Object.Command.CanExecute(null));
}
Sometimes (NOT ALWAYS) when Jenkins does the build and run unit tests some of can execute tests failed with message:
MESSAGE:
Expected: True
But was: False
+++++++++++++++++++
STACK TRACE:
at Project.CommandCanExecute(Boolean inEditMode, Boolean expectedResult)
The problem is that is happening only on Jenkins and it's very nondeterministic.
EDIT:
Ok, one more thing to think about. Property InEditMode is placed in base parent class of SomeModelView.
And I merged code for you in the sample.
public BaseViewModel
{
public virtual bool InEditMode {get; set;}
}
public SomeViewModel : BaseViewModel
{
public SomeViewModel () : base ()
{
}
public ICommand Command { get; set; }
public virtual void RegisterCommands()
{
Command = new RelayCommand(/*Do something*/, () => InEditMode);
}
}
And we think that can be related, that object is thinking that is initialized before initialization of base class is done. But that is very hard to check this with a Jenkins.
I've created an attribute class:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Assembly, AllowMultiple = true)]
public class GarbageCollectorDisabler : Attribute, ITestAction
{
public void BeforeTest(ITest test)
{
GC.TryStartNoGCRegion(2048 * 4096);
}
public void AfterTest(ITest test)
{
GC.EndNoGCRegion();
}
public ActionTargets Targets => ActionTargets.Test;
}
And then I can use for each 'CanExecute' test this attribute:
[GarbageCollectorDisabler]
[TestCase(TestName = "SomeTest_InEditMode_CanExecute")]
public void SomeTestCanExecute()
{}
Smells like a garbage collection issue to me. I don't see anything that jumps out at me in your sample, though the code sample is incomplete (where is RegisterCommands
invoked?) so something crucial could be missing.
See the source for RelayCommand.CanExecute()
. It takes a weak reference to the action you pass in, and once that action is collected CanExecute
will return false
. See my answer here for an example of this happening.
I reiterate @Nkosi's comment, create a minimal example rather than showing us bits and pieces.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With