Moq Verify Not Working as Expected After Upgrading to .NET Core 3.1 - unit-testing

So as the title implies, this worked for us in .NET Core 2.2 and Moq Version 4.10.1. After upgrading to .NET Core 3.1 and Moq Version 4.14.5, the verify method is failing saying the method specified hasn't been called (no changes to the underlying code). I rolled back Moq to version 4.10.1 just to see if it was due to a change within the new version of Moq. I still get the same error.
Trying to verify that a log message has been written to the ILogger.
Weird thing is, if I debug the unit test and look at the mocked object with a variable watch, it shows that the method has indeed been invoked.
Relevant code:
public class AuditFilter, IResultFilter
{
...
public void OnResultExecuted( ResultExecutedContext context )
{
if( !IsContextValid( context ) )
{ return; }
...
}
public override bool IsContextValid( FilterContext context )
{
if( context == null )
{
Logger.Error( "Error writing to the audit log", new ArgumentNullException( nameof( context ) ) );
return false;
}
if( context.HttpContext == null )
{
Logger.LogError( "Error writing to the audit log", new ArgumentNullException( nameof( context.HttpContext ) ) );
return false;
}
return true;
}
public ILogger Logger { get; set; }
...
}
public class AuditTests : BaseTests
{
...
private Mock<ILogger> _mockLog;
private AuditFilter _filter;
[SetUp]
public void Setup()
{
_mockLog = new Mock<Microsoft.Extensions.Logging.ILogger>();
_mockLog.SetupAllProperties;
_filter = new AuditFilter();
}
[Test]
public void Service_Filters_Audit_IsContextValid_Context_Null()
{
var expected = false;
_filter.Logger = _mockLog.Object;
var actual = _filter.IsContextValid( null );
_mockLog.Verify( logger => logger.Log( LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<object>(),
It.IsAny<ArgumentNullException>(),
It.IsAny<Func<object, Exception, string>>() ),
Times.Once );
Assert.AreEqual( expected, actual );
}
...
}
Note: The method ILogger.LogError is a Microsoft extension method for ILogger that calls ILogger.Log method.
Below is the exception that is thrown.
Note: An integer implicitly casts to Microsoft.Extensions.Logging.EventId, the second input parameter type for the ILogger.Log method.
These signatures appear to match to me; so I'm not sure why it's saying it wasn't invoked.
To reiterate, this code worked prior to upgrading to .NET Core 3.1 and still works in our pre-forked code.
Also, before someone suggests that the method needs to be setup: it worked before the upgrade without it, and I already tried it and it didn't work.

I believe the problem will be this part of the verify expression
It.IsAny<Func<object, Exception, string>>()
Under the covers it's not a Func<object, Exception, string> and the mock IsAny matcher doesn't match because of this difference. If you modify it to
(Func<object, Exception, string>) It.IsAny<object>()
it should match. Below is what I've settled on as the starting point for verify expressions as it works for at least .NET Core 2.* onwards:
loggerMock.Verify(x => x.Log(
It.IsAny<LogLevel>(),
It.IsAny<EventId>(),
It.IsAny<IReadOnlyList<KeyValuePair<string, object>>>(),
It.IsAny<Exception>(),
(Func<object, Exception, string>) It.IsAny<object>()),
Times.Exactly(expectedNumberOfInvocations));
You can use It.IsAny<object>() for the third parameter but I find this is more convenient when interrogating the properties.
I've been doing a fair bit of log invocation verification at work recently for black box processes so now I mostly use Moq.Contrib.ExpressionBuilders.Logging to build fluent, readable verify expressions. Disclaimer: I am the author.

Like I had added in the comments, this is a known issue with Moq and .NET Core right from the Preview version of .NET Core 3.0. Please take a look at the github issue to understand why this broke with the update.
In a nutshell, from the issue linked, the failure here is caused due to fact that the type being passed to Logger.Log method is now changed to FormattedLogValues. Though there is a generic type matcher It.IsAnyType introduced in Moq 4.13.0, that would not address the issue.
The reason for this, as one of the authors of Moq states here
The important bit (for now) is that It.IsAnyType is not used in a nested position in the It.IsAny<> type argument.
As a workaround we should replace
It.IsAny<Func<object, Exception, string>>()
with
(Func<object, Exception, string>)It.IsAny<object>()
The rationale provided for this, is to improve the performance of the type matcher as the former would result in the decomposition of all the type parameters underneath the hood to see if there is a type matcher included in the first place.

Related

Override System class in Java and more precisely currentTimeMillis [duplicate]

Aside from recompiling rt.jar is there any way I can replace the currentTimeMillis() call with one of my own?
1# The right way to do it is use a Clock object and abstract time.
I know it but we'll be running code developed by an endless number of developers that have not implemented Clock or have made an implementation of their own.
2# Use a mock tool like JMockit to mock that class.
Even though that only works with Hotspot disabled -Xint and we have success using the code bellow it does not "persist" on external libraries. Meaning that you'd have to Mock it everywhere which, as the code is out of our control, is not feasible. All code under main() does return 0 milis (as from the example) but a new DateTime() will return the actual system millis.
#MockClass(realClass = System.class)
public class SystemMock extends MockUp<System> {
// returns 1970-01-01
#Mock public static long currentTimeMillis() { return 0; }
}
3# Re-declare System on start up by using -Xbootclasspath/p (edited)
While possible, and though you can create/alter methods, the one in question is declared as public static native long currentTimeMillis();. You cannot change it's declaration without digging into Sun's proprietary and native code which would make this an exercise of reverse engineering and hardly a stable approach.
All recent SUN JVM crash with the following error:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000, pid=4668, tid=5736
4# Use a custom ClassLoader (new test as suggested on the comments)
While trivial to replace the system CL using -Djava.system.class.loader JVM actually loads up the custom classLoader resorting to the default classLoader and System is not even pushed trough the custom CL.
public class SimpleClassLoader extends ClassLoader {
public SimpleClassLoader(ClassLoader classLoader) {
super(classLoader);
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return super.loadClass(name);
}
}
We can see that java.lang.System is loaded from rt.jar using java -verbose:class
Line 15: [Loaded java.lang.System from C:\jdk1.7.0_25\jre\lib\rt.jar]
I'm running out of options.
Is there some approach I'm missing?
You could use an AspectJ compiler/weaver to compile/weave the problematic user code, replacing the calls to java.lang.System.currentTimeMillis() with your own code. The following aspect will just do that:
public aspect CurrentTimeInMillisMethodCallChanger {
long around():
call(public static native long java.lang.System.currentTimeMillis())
&& within(user.code.base.pckg.*) {
return 0; //provide your own implementation returning a long
}
}
I'm not 100% sure if I oversee something here, but you can create your own System class like this:
public static class System {
static PrintStream err = System.err;
static InputStream in = System.in;
static PrintStream out = System.out;
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) {
System.arraycopy(src, srcPos, dest, destPos, length);
}
// ... and so on with all methods (currently 26) except `currentTimeMillis()`
static long currentTimeMillis() {
return 4711L; // Your application specific clock value
}
}
than import your own System class in every java file. Reorganize imports in Eclipse should do the trick.
And than all java files should use your applicatikon specific System class.
As I said, not a nice solution because you will need to maintain your System class whenever Java changes the original one. Also you must make sure, that always your class is used.
As discussed in the comments, it is possible that option #3 in the original question has actually worked, successfully replacing the default System class.
If that is true, then application code which calls currentTimeMillis() will be calling the replacement, as expected.
Perhaps unexpectedly, core classes like java.util.Timer would also get the replacement!
If all of the above are true, then the root cause of the crash could be the successful replacement of the System class.
To test, you could instead replace System with a copy that is functionally identical to the original to see if the crashes disappear.
Unfortunately, if this answer turns out to be correct, it would seem that we have a new question. :) It might go like this:
"How do you provide an altered System.currentTimeMillis() to application classes, but leave the default implementation in place for core classes?"
i've tried using javassist to remove the native currentTimeMills, add a pure java one and load it using bootclasspath/p, but i got the same exception access violation as you did. i believe that's probably because of the native method registerNatives that's called in the static block but it's really too much to disassemble the native library.
so, instead of changing the System.currentTimeMills, how about changing the user code? if the user code already compiled (you don't have source code), we can use tools like findbugs to identify the use of currentTimeMillis and reject the code (maybe we can even replace the call to currentTimeMills with your own implementation).

Eclipse CDT: Problems with extension point CIndexer

Problem 1: I can't find org.eclipse.cdt.core.index.IIndexer
From the API:
API Information: Plug-ins that want to extend this extension point must implement org.eclipse.cdt.core.index.IIndexer interface.
Is the API Information incorrect/deprecated? Which interface should be implemented if not IIndexer?
Problem 2: I can install my own Indexer in CDT version 6.8 (eclipse 2019-06) but not in version 6.5 (eclipse 2018-09), though I don't see the difference in the plugin code.
More Details:
My Indexer class:
#SuppressWarnings("restriction")
public class MyIndexer extends PDOMFastIndexer {
public static final String ID = "de.blub.MyIndexer";
#Override
public String getID() {
return ID;
}
#Override
public IPDOMIndexerTask createTask(ITranslationUnit[] added, ITranslationUnit[] changed,
ITranslationUnit[] removed) {
if (...) {
return new MyIndexerTask(added, changed, removed, this, true);
} else {
return super.createTask(added, changed, removed);
}
}
The plugin.xml
<extension
id="org.eclipse.cdt.core.fastIndexer"
name="My Indexer"
point="org.eclipse.cdt.core.CIndexer">
<run
class="de.blub.MyIndexer">
</run>
The MANIFEST.MF File lists org.eclipse.cdt.core in the Require-Bundle section without bundle-version. Of course the cdt plugin has different versions:
In Eclipse 2019-06:
Eclipse CDT C/C++ Development Tools Core 6.8.1.201907021957 org.eclipse.cdt.core
In Eclipse 2018-09:
Eclipse CDT C/C++ Development Tools Core 6.5.0.201811180605 org.eclipse.cdt.core
This code is from org.eclipse.cdt.internal.core.pdom.PDOMManager:
private IPDOMIndexer newIndexer(String indexerId, Properties props) throws CoreException {
IPDOMIndexer indexer = null;
// Look up in extension point
IExtension indexerExt = Platform.getExtensionRegistry().getExtension(CCorePlugin.INDEXER_UNIQ_ID, indexerId);
if (indexerExt != null) {
IConfigurationElement[] elements = indexerExt.getConfigurationElements();
for (IConfigurationElement element : elements) {
if ("run".equals(element.getName())) { //$NON-NLS-1$
try {
indexer = (IPDOMIndexer) element.createExecutableExtension("class"); //$NON-NLS-1$
indexer.setProperties(props);
} catch (CoreException e) {
CCorePlugin.log(e);
}
break;
}
}
}
// Unknown index, default to the null one
if (indexer == null)
indexer = new PDOMNullIndexer();
return indexer;
}
The code is the same for both cdt versions. indexer becomes a PDOMFastIndexer in eclipse 2018-09, but a MyIndexer in 2019-06.
One difference I could see is that in RegistryObjectManager
private Object basicGetObject(int id, byte type) {
Object result = cache.get(id);
if (result != null)
return result;
...
}
An id is used to get the correct ConfigurationElement (result) from a cache object, which I don't really understand how it is built up. However, the returned ConfigurationElement contains a field propertiesAnsValues which is incorrect in the one case (org.eclipse.cdt.internal.core.pdom.indexer.PDOMFastIndexer instead of de.blub.MyIndexer).
How can I fix that to have my own indexer in eclipse 2018-09, too?
Please also note my Problem 1. Because if the API description is correct, it means I'm trying to install my indexer the wrong way and need to do something to 'see' the IIndexer interface.
According to the schema definition, the class you need to derive from is IPDOMIndexer (which you're already doing). You can also tell this from the PDOMManager code you quoted, which casts the result of createExecutableExtension() to IPDOMIndexer.
(The comment saying to use org.eclipse.cdt.core.index.IIndexer is indeed out of date. Based on a brief look, that interface hasn't existed since at least 2005. Patches to update the extension point documentation are welcome.)
As for your second problem, I believe it's because you're using id="org.eclipse.cdt.core.fastIndexer" for your extension, which is already in use by one of CDT's built-in indexers. The id needs to identify your extension uniquely (so you can make it something like myproject.MyIndexer.)

getting InvalidUseOfMatchersException in a proper use of matchers

Everything sounds correct but I get org.mockito.exceptions.misusing.InvalidUseOfMatchersException, when I try to mock a protected method.How Can I solve it ?
private Service service;
private System system;
#BeforeMethod
public void setupMocks() throws Exception {
service = powerMock.mock(Service.class);
system = powerMock.mock(System.class);
}
public void sample_Test() {
PowerMockito.doReturn(system).when(service, "getValidatedDto",
Matchers.any(Long.class), Matchers.any(Date.class));
// some code
}
I suspect you are seeing this exception:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
4 matchers expected, 2 recorded:
With this additional context:
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
If so, then this is because you are mixing parameters in the form of matchers (Matchers.any(Long.class), Matchers.any(Date.class)) with parameters in the form of raw values (service, "getValidatedDto").
The signature of the method under test is unclear to me but I think it might be something like
System getValidatedDto(Long aLong, Date aDate);
If so, then the correct invocation would be:
PowerMockito.doReturn(system).when(service).getValidatedDto(
Matchers.any(Long.class), Matchers.any(Date.class));

Mockito - Invalid use of argument matchers

I have Junit test that is testing jms message sending. I am using Spring jmsTemplate to to do this. Here I as in the following code I want to check whether the JMS template has called send message regardless what is it in the values of actuall parameters that are passed.
my publisher method the uses the jmsTemplate to send method looks like following inside..
jmsTemplate.send(jmsQueueProperties.getProperty(key), new MessageCreator()
{
public Message createMessage(Session session) throws JMSException
{
ObjectMessage obj = session.createObjectMessage(dialogueServiceResponse);
return obj;
}
});
in My tests..
JmsTemplate mockTemplate = Mockito.mock(JmsTemplate.class);
...
publisher.publishServiceMessage(response);
....
Mockito.verify(mockTemplate,
Mockito.times(1)).send("appointment.queue",
Mockito.any(MessageCreator.class));
But when in the execution i get
org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!
....
Cause is due to Mockito.any(MessageCreator.class) , but isn't there a way to test my send method is getting executed without creating an actual object in the MessageCreator.
Update
And is there a way to check my session.createObjectMessage(dialogueServiceResponse) is getting called as well
I think the rest of the message tells you what the problem is. When you use an argument matcher for one of the arguments, all the other arguments must also use an argument matcher:
Mockito.verify(mockTemplate, Mockito.times(1)).send(
Mockito.eq("appointment.queue"),
Mockito.any(MessageCreator.class));
For future readers. This will save you a lot of time.
We cannot use argument matcher and primitive/raw values together.
when(fooService.getResult("string",any(MyClass.class))).thenReturn(1); // will give error
when(fooService.getResult(anyString(),any(MyClass.class))).thenReturn(1); // correct
I think you cannot use argument matchers outside stubbing. I also got the same error but when I return, I had to do new string() instead of Mockito.anyString() and the error goes away.
Example:
Mockito.when(mockedBean.mockedMethod(Mockito.anyString(),
Mockito.anyInt(),
Mockito.anyInt(),
Mockito.anyInt(),
Mockito.anyBoolean())).thenReturn(new String());
I can see that this question is about Java code, but I will share this because we use Mockito in Scala as well.
I had this exception thrown from the following code that mocks Play.api configurations
"Configurations Service" should {
"return all dataset configurations" in {
val configs = mock[Configuration]
val testData = Seq("SOME VALUE")
val loader = any[ConfigLoader[Seq[String]]]
when(configs.get[Seq[String]](any[String])).thenReturn(testData) // EXCEPTIONN HERE !
val configuration: ConfigurationsService = new ConfigurationsService(configs)
assert(configuration.getSupportedDatasets() == testData)
}
}
In Scala methods can have Implicit parameters configs.get method has one explicit param and an Implicit one I passed a mock object and when an exception was thrown I was wondering what is going on as I didn't MIX params and mocks, it turned out that I had to pass mocks to implicit parameters as well, and this solved the problem.
val loader = any[ConfigLoader[Seq[String]]] // configs.get has one implicit parameter that accepts ConfigLoader[Seq[String]]
when(configs.get[Seq[String]](any[String])(loader)).thenReturn(testData)
I was seeing this error about a mismatched # of arguments, despite having the correct number...
I realized this was because method being stubbed was static. When I converted it to non-static, it worked as expected.

WP7: Getting started with UnitTest Framework: XamlParseException

I want to add Unit Tests to my WP7 project. I followed the tutrials on http://smartypantscoding.com/a-cheat-sheet-for-unit-testing-silverlight-apps-on-windows-phone-7 to get started with unit tests. But I cannot manage to get it running.
I followed all the steps from the tutorial and created the basictests.
But as soon as I want to start the project, Visual Studio throws an error:
XamlParseException occured
Cannot find a Resource with the Name/Key typeNameConverter [Line: 47 Position: 24]
Line 47 refers to the initial CreateTestPage:
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
SystemTray.IsVisible = false;
Line47: var testPage = UnitTestSystem.CreateTestPage() as IMobileTestPage;
BackKeyPress += (x, xe) => xe.Cancel = testPage.NavigateBack();
(Application.Current.RootVisual as PhoneApplicationFrame).Content = testPage;
}
Hope you can help me out!
thank you!
You are probably using Jeff Willcox's toolkit for Windows Phone 7. If you want to run it under new Windows Phone try to use new version of toolkit as I did.
Try to use Jeff Willcox's toolkit for Windows Phone 7.5 (Mango) Get it here: http://www.jeff.wilcox.name/2011/06/updated-ut-mango-bits/
Good luck.
I encountered this yesterday and found that App.xaml was misconfigured. Using guesswork (i.e. what interfaces implement IValueConverter?), I found this solution, which seems to work very well.
First, add this namespace to your <Application> namespace:
xmlns:Client="clr-namespace:Microsoft.Silverlight.Testing.Client;assembly=Microsoft.Silverlight.Testing">
Then add this to <Application>:
<Application.Resources>
<Client:TypeNameVisibilityConverter x:Name="typeNameConverter" />
<Client:FontWeightConverter x:Name="fontWeightConverter" />
</Application.Resources>
I hope this is useful to someone.
I can confirm that Michael Dumont's solution does work as well, but you can't view test run details which is annoying when attempting to view information for broken tests when you don't have the debugger attached for whatever reason.
Make sure your Unit test project is for .Net Framework 3.0 or 3.5 and use the Unit Test Framework Assemblies compatible with Mango created by Jeff Wilcox. I had the same error when the project is for .Net Framework 4.0.
I received this error as well and stubbed the ValueConverters it was looking for and was able to successfully get the framework working.
App.xaml
<!--Application Resources-->
<Application.Resources>
<s:typeNameConverter x:Name="typeNameConverter"></s:typeNameConverter>
<s:fontWeightConverter x:Name="fontWeightConverter"></s:fontWeightConverter>
</Application.Resources>
Value Converters
public class typeNameConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
public class fontWeightConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
And the exception refers to the XAML in the TestPage. So you're posting the wrong code.
Anyway, the error is very clear. The declared typeNameConverter in your XAML, is missing. Most likely you forgot to add a reference to the assembly declaring it, or to update the xmlns so it points on a different assembly, and not just a different namespace.