- Notifications
You must be signed in to change notification settings - Fork 45
Force mocking without mock framework installed fix #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| fun shouldMock( | ||
| type: RefType, | ||
| mockInfo: UtMockInfo, | ||
| ): Boolean = doShouldMock(type, mockInfo).also { mockListenerController.onShouldMock(strategy, it) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we emit an event if and only if doShouldMock returns true?
| import kotlinx.coroutines.currentCoroutineContext | ||
| import kotlinx.coroutines.CancellationException | ||
| import kotlinx.coroutines.Job | ||
| import kotlinx.coroutines.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct your Intellij Idea settings to avoid wildcard imports, please. In my situation it was reset after the update of IDE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check it in other files of this PR too, please
| ) | ||
| } | ||
| | ||
| fun attachMockListener(mockListener: MockListener) = mocker.mockListenerController.attach(mockListener) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's discuss why this code is a pat of engine, may be there is a very unclear relation here
| import org.utbot.engine.util.mockListeners.exceptions.ForceMockCancellationException | ||
| | ||
| /** | ||
| * Listener for mocker events in symbolic engine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is always better to mention entities in comments as named references like [UtSymbolicEngine]
| * Supposed to be created only if Mockito is not installed. | ||
| */ | ||
| class ForceMockListener: MockListener { | ||
| var forceMockHappened = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's avoid public setter on it
| // If force mocking happened | ||
| if (shouldMock) { | ||
| // Cancel engine job | ||
| controller.job!!.cancel(ForceMockCancellationException()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we would never like to crash here. Suggest to do like this
controller.job?.let { ForceMockCancellationException() }
| * Controller that allows to attach listeners to mocker in symbolic engine. | ||
| */ | ||
| class MockListenerController(private val controller: EngineController) { | ||
| val listeners = mutableListOf<MockListener>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What other listeners except MockListener may be in MockListenerController?
| if (model.forceMockingHappened) { | ||
| val warningMessage = """ | ||
| Warning: Some test cases were ignored, because no mocking framework is installed in the project. | ||
| Better results could be achieved by <a href="${TestReportUrlOpeningListener.prefix}${TestReportUrlOpeningListener.mockitoSuffix}">installing mocking framework</a>, e.g. Mockito. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like "e. g. Mockito"
If user install another framework. it will not help him. More than that, mockito-core with the version startting from 3.. is required to him.
| if (createMockFrameworkNotificationDialog("Configure mock framework") == Messages.YES) { | ||
| configureMockFramework(project!!, module!!) | ||
| } | ||
| } ?: error("Could not configure mock framework: null in module ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need module or project name here: these message in logs will be just scaring
| private val defaultListener = NotificationListener.UrlOpeningListener(false) | ||
| | ||
| // Last project and module to be able to use them when activated for configuration tasks. | ||
| var project: Project? = null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should they really be nullable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
configureMockFramework(project!!, module!!) is very bad later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, they should really be nullable. The other approach is to use lateinit var, but this will cause tight coupling with TestReportNotifier and force initialization of such properties at some point in the caller code, which is not obvious.
| | ||
| private fun handleDescription(descriptionSuffix: String) { | ||
| when { | ||
| descriptionSuffix.startsWith(mockitoSuffix) -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be we should store a list of all possible suffixes and do smth like when here?
| } | ||
| | ||
| forceMockListener?.run { | ||
| model.forceMockingHappened = forceMockHappened |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the names similar, please
| val notifyMessage = buildString { | ||
| appendHtmlLine(testsCodeWithTestReport.testsGenerationReport.toString()) | ||
| appendHtmlLine() | ||
| if (model.forceMockingHappened) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it is not very scalable solution, but I'm not sure it is easy to do better.
| } | ||
| else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Odd formatting
| descriptionSuffix.startsWith(mockitoSuffix) -> { | ||
| project?.let { module?.let { | ||
| if (createMockFrameworkNotificationDialog("Configure mock framework") == Messages.YES) { | ||
| configureMockFramework(project!!, module!!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use it for the module and introduce a variable for the project. Otherwise, why would you use let instead of just if
| mockInfo: UtMockInfo, | ||
| ): Boolean = doShouldMock(type, mockInfo).also { mockListenerController.onShouldMock(strategy, it) } | ||
| | ||
| private fun doShouldMock( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is a strange name. checkIfShouldMock or something like that might be more suitable
| private val strategy: MockStrategy, | ||
| private val classUnderTest: ClassId, | ||
| private val hierarchy: Hierarchy, | ||
| internal val mockListenerController: MockListenerController, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that it is a good idea for the Mocker to have a mandatory field with the controller. What if I don't know anything about it and just want to check whether some field would be mocked or not? What should I pass here? Or now Mocker cannot work without the engine (more specifically, without a current version of the engine, with the controller)
| ForceMockListener().apply { | ||
| codeGenerator.generator.configureEngine = { engine -> engine.attachMockListener(this) } | ||
| } | ||
| } else null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I've mentioned many times, brackets
| Approve in accordance with our verbal discussion on improvements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an odd-looking connection between the mocker, its controllers, engine controllers and listeners. Seems like it is a problem with the design and it might cause further problems with engine refactorings and separation of the virtual machine and traverse
Approved since the PR contains required fix and need to be tested ASAP
5bb59b3 to 1be046f Compare Added mock listeners for engine. Added force mock listener. Added url handler for urls like "#utbot/...". Added message with link to mock framework configuration to test reports if force mocking happened.
1be046f to 3d34399 Compare
Description
Added mock listeners for engine to make it abstract from external events.
Added force mock listener.
Added url handler for urls like "#utbot/..." to launch configuration tasks from popups.
Added message with link to mock framework configuration to test reports if force mocking happened.
Fixes #190
Type of Change
Please delete options that are not relevant.
How Has This Been Tested?
Manual Scenario
Launched project without mockito installed.
Generated tests for Sort.quickSort without mocks -> mocks for Random were forced.
Checked that message suggesting mockito installation appeared in test report.
Verified that link in that message leads to the window for mockito configuration, and it installs correctly.
After installation, tests with force-mocks were generated correctly.
Checklist (remove irrelevant options):