-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Unit test projects can't reference Maui multi target projects #3552
Comments
Just some thoughts! In the pure MVVM world your view models should not have references to UI components. This is so they can be unit tested!! Which is your problem here. So what other references do you have? Also it is possible to create another testing project which just has file links to the view models. And then run your unit tests against this. You could also exclude other references by #if in the files and setting a TEST define in the unit test project. |
@devmikew I agree, view models should not have references to UI components. Mine don't, they just happen to live in the same project as the views. They don't have to, as I mentioned. But I like to keep views and models organised. Then consider platform specific implementations for any dependencies that view models might need, lets say a ICalendarRepository with a concrete implementation for each platform. Lets add a Calendars Maui project with the actual platform specific code, the interface definition can also be in the same project. You can't then mock that interface in a test because I can't reference the Maui project from a test project. I can create a separate project just for the interface, but that feels like massive overkill. |
The ICalendarRepository seems to be a data/business layer. Couldn't you add a net6.0 target framework for this (the repository) project and in that target framework implementation do nothing. Normally you would only target android/ios/windows in this project as these are the real runtime platforms. |
Not sure I follow your suggestion, concrete implementations of ICalendarRepository would be to access iOS EKEvents, Android calendar, Windows Appointments etc in a generic way. It isn't business logic, but it is native data access. The platform specific implementation of ICalendarRepository is DI'ed into the VM constructor. The logic is held in the VM. The VM needs to be unit tested and I would need to mock ICalendarRepository (and any other dependencies it has). I can't though as the unit test project can't access the multi target library Maui projects. As I said, I could move the interfaces into a .net 6 project, I just don't think I should have to. |
Sorry, but what I tried to say, was to provide an implementation for net-6.0. This implementation does not need to do anything except return a valid result.
Get Outlook for Android<https://aka.ms/AAb9ysg>
…________________________________
From: JohnHDev ***@***.***>
Sent: Friday, November 26, 2021 9:07:31 AM
To: dotnet/maui ***@***.***>
Cc: devmikew ***@***.***>; Mention ***@***.***>
Subject: Re: [dotnet/maui] Unit test projects can't reference Maui multi target projects (Issue #3552)
Not sure I follow your suggestion, concrete implementations of ICalendarRepository would be to access iOS EKEvents, Android calendar, Windows Appointments etc in a generic way. It isn't business logic, but it is native data access.
The platform specific implementation of ICalendarRepository is DI'ed into the VM constructor. The logic is held in the VM. The VM needs to be unit tested and I would need to mock ICalendarRepository (and any other dependencies it has). I can't though as the unit test project can't access the multi target library Maui projects.
As I said, I could move the interfaces into a .net 6 project, I just don't think I should have to.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#3552 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AKBBNIJ3RZD4S75USOEGJ5DUN26THANCNFSM5IZJFLGA>.
Triage notifications on the go with GitHub Mobile for iOS<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675> or Android<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
I am talking about mocking ICalendarRepository in a test, it has nothing to do with concrete implementations. |
Please see how it is implemented in Community toolkit https://github.com/CommunityToolkit/Maui/blob/main/src/CommunityToolkit.Maui.UnitTests/CommunityToolkit.Maui.UnitTests.csproj |
@VladislavAntonyuk thanks, I have updated my project to match (including removing nunit and adding xunit) but Im not seeing any difference. What is the magic ingredient with that? |
could you share your simple project to reproduce the issue? most likely you have some dependencies which cannot be resolved |
Here is a very simple example, new Maui solution, added a MainPageModel, added a unit test project, added reference to the maui project in the unit test project, it is not compatible. The unit test project would contain tests for the MainPageModel but obviously can't get that far. |
Its a Maui project that also generates the apps, so it really should not make any difference. Ok, so try this one: I have moved the MainPageModel into its own .net 6 project, and added a reference to an interface held in a new Maui project. It not build because .net 6 projects can't reference .net maui projects. As I said, I can fix that by moving the ICalendarRepository into a separate .net 6 project, but we shouldn't have to. |
you are doing it wrong. you are trying to add maui library to net6.0 library. it is not correct. |
That is exactly what I said I could do, but shouldn't have to. What if I wanted to create a nuget for a Maui project? It would need 2 project files, 1 for the implementation, and 1 just for the interfaces. That is certainly possible, but imo poor design. This is the point I have raised in creating this card. |
You can change your test project to support the same frameworks as your Maui project. In that case it should work. |
I have a sample working with the maui project targeting net6.0. This allows the test project to reference the maui project and the repository project (assuming its net6.0). The maui project also references the repository project. You can run tests on the repository project either directly or through the maui project. However there are some problems: . i had to do a lot of fiddling to get the maui project to compile on all frameworks. . I think most of the problems were to do with the project system/build system. Eg, I had to continually close and re-open VS or delete the project.assets.json and restore. . the maui project just degrades to the view models and whatever helpers are needed. . so i wondered was it worth it, eg, why not have a vm assembly? .a zip is attached if your interested. |
Attached is a sample project and tests where the VMs and helpers are linked into another project. |
@devmikew thank you for the sample, but I don't see how that would work, you don't have platform specific implementations for the repository, which means it isn't using MAUI at all other than for the UI. |
Maybe you should use device test instead of unit test. |
The projects I sent only provide the scaffolding for a possible implementation. Eg:
|
@devmikew thanks, I appreciate your efforts! Imo, .net 6 projects should be able to reference .net maui projects, in so far as being able to only reference anything in those projects that are not in the platforms folder. This is a much cleaner and simpler design and makes mocking and unit testing a breeze. |
@JohnHDev It is obvious that it can be done, 'like elephants mating'. I think the only easy, and testable way, is for Maui to target net6.0. I imagine this would be non-trivial. Eg, it would require a lot of refractoring and split up of the maui assembly into different components. Maybe that is not a bad thing, as how many developers in the future are going to be facing the same struggles. |
@devmikew Maui can't target net6.0. It doesn't make any sense. Net6.0 is like netstandard (like abstract class), which only describes what you can do in all platforms. For specific implementation you target specific framework like met6.0-Android, which gives you access to Android api. |
After a little inspection, maui does target net6.0. It seems to have most of the code compiled, however there is a broken reference to Microsoft. Maui Graphics. So I'm going to dog a bit deeper over the weekend. |
Hey @devmikew, did you resolve a more straightforward solution to performing unit test on a MAUI project? |
Verified Repro with Android 11. Repro Project is available: |
Is there any plan so it is possible to reference Maui multi target projects for Unit testing? The different solutions mentioned previously are just a workaround in my opinion, it is true that is good practice to separate business logic in another library, but MAUI should be testable as a single project. |
@Hottemax I was able to successfully run xUnit tests against MAUI project adding a compiler constant for net6 target and adding a missing fake entry point for net6 only. Like so: In the MAUI app
<TargetFrameworks>net6.0;net6.0-android;net6.0-ios;net6.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net6.0-windows10.0.19041.0</TargetFrameworks>
<PropertyGroup Condition="$(TargetFramework) == 'net6.0'">
<DefineConstants>$(DefineConstants);NET6_TARGET</DefineConstants>
</PropertyGroup> If you try to build the app, will raise an error:
So, to fix that, In the MAUI app #if NET6_TARGET
public static void Main(string[] args) {}
#endif Now, the MAUI app is building and you can reference it in the xUnit test project. The only requirements for the unit test project are: <TargetFramework>net6.0</TargetFramework>
<UseMaui>true</UseMaui> Keep in mind that I only tested this in a new blank MAUI app, so, I'm not sure about other blockers that may have. |
@deividt I tried your approach just now in a project with ~300 unit tests, many of which are testing view models and controls from a Maui app multitarget project, and it worked great! Some tests are even passing 😝 I initially had an issue running the Maui app project on Windows after adding net6.0 as a target framework, even though it would build fine: Building would not resolve. Curious to know if your Maui app project still deploys OK, even after uninstalling and doing a clean/rebuild? It looked to me like it was trying to launch the app from the bin/debug/net6.0 folder instead of the net6.0-windows10.0.19041.0 folder. So I moved the net6.0 target framework to be last, after mac catalyst, reloaded the csproj, and it seemed to kick into gear and deployed the WinUI app successfully. Thanks for sharing this! |
@breenbob, I'm happy to know that this approach worked. 😄 Though I just did some tests and I don't have real apps running, even didn't test in windows, so I don't have enough information to give you about the deployment. Now that you mentioned about the order of the target framework. I've also noticed something similar, if I put it in different places (e.g. after the definition of Another approach that I was trying, was just adding the net6 target conditionally, but I didn't have success with that.
|
Hey everyone, thanks for all the input! We definitely need to make this story better. A while back I got this question from someone and I came up with this: https://github.com/jfversluis/MauiUnitTestSample the changes needed are in the 2 csproj files and marked with a comment that starts with I think it's pretty similar to what @deividt has been doing |
Hey @jfversluis, your approach worked in my project too. Thanks for sharing. |
This may or may not be related, but after applying the changes as described by @jfversluis , and firing up my (NUnit) tests, it barks at calls to |
@ericnev This is expected behaviour since your unit tests are targetting If you read the source code for You will need to use the interfaces for the This approach was what we used in Xamarin with the |
I can move this discussion to somewhere else if it's not the appropriate venue, but.. there's a bit of a catch-22 here. If I target I should be clear that I'd prefer to run the tests using
|
For those looking for a way to unit test their viewmodels by referencing a .NET6 version of the MAUI single project, here is a few csproj tricks to help you out. It isn't perfect, but will get you most of the way https://gist.github.com/aritchie/fa5be94f831f0fe9aaefd22b029915d7 |
Am I reading this right? It's not possible, through Visual Studio directly, to create unit tests for .NET MAUI projects? That we need to dive into the .csproj to make things work (or just extract the model classes and put them in a separate, console-based (say) application)? |
i wrote a blog post about this here https://codingistherapeutic.com/2022/10/19/unit-testing-a-net-maui-app-with-platform-specific-code/. Also i did recently see with a new .net maui application that the Unit Testing project doesnt have the true and it built and ran test without an issue, even referencing ViewModels. so there could be some potential there |
Again, those are all workarounds in order to solve a design fault. If you add net6.0 in the target frameworks, whenever you start using implementation specific code in your project, you enter into the nightmare realm of #if #else compilator hell. No plans to address this issue with the launch of net7.0? |
@ismasanchez I don't see this as a design fault at all. MAUI gives you the standard interfaces on net60, not just the platforms. The xaml fails to compile properly right now, it is easy to move that out of the with csproj. If you think that this is truly a design flaw, how would you solve this? You really 3 options
|
In my opinion, there should be at least two options, number 2 that you mentioned is adequate, but is not enough, a MAUI project should be able to be referenced by libraries requiring .net6 without any workaround. |
my solution to this issue only required 1 #if condition in the shared platform specific code and very minimal change to the csproj. i do agree that it shouldnt be required to have to make such changes but as i mentioned before "i did recently see with a new .net maui application that the Unit Testing project doesnt have the true and it built and ran test without an issue, even referencing ViewModels. so there could be some potential there" |
I just had the same problem. |
This should now be fixed with .NET 8 preview 2. Let me test and confirm... |
Description
With the new design for multi target projects, we need to be able to unit test ViewModels stored in Maui projects.
We could move ViewModels into pure .net 6 projects, but dependencies that are defined in other multi target projects with platform specific implementations can't be mocked regardless without also moving the interfaces for those dependencies into .net 6 projects. That largely negates the positives of multi target projects if we have to create other projects just to contain the Interface definitions and view models.
Steps to Reproduce
Create a .NET Maui solution
Create a ViewModel to the .NET Maui project.
Create a unit test project and add a reference to the .NET Maui project.
Version with bug
Preview 10 (current)
Last version that worked well
Unknown/Other
Affected platforms
I was not able test on other platforms
Affected platform versions
All
Did you find any workaround?
Create another .net 6 project for view modals and interfaces that the tests and .net maui projects can reference.
That just doesn't scale well.
Relevant log output
No response
The text was updated successfully, but these errors were encountered: