I'm trying to create an integration test in .NET Core 2.1 with the latest Visual Studio 2017 build. There is nothing special about my setup whatsoever.
If I put the "async" keyword on a test, as is needed to test async methods, VS will terminate before attempting to run any tests with a FileNotFound exception. The missing file is "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.resources".
So the question (other than 'how does Microsoft keep managing to release such broken frameworks') is: Why?
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ServiceClients.IntegrationTests
{
[TestClass]
public class SicklyUnitTest
{
[TestInitialize]
public void Initialize()
{
}
// This is fine
[TestMethod]
public void TrueIsTrue()
{
Assert.IsTrue(true);
}
// This causes FileNotFound - "Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.resources"
[TestMethod]
public async void DeOmnibusDubitandum()
{
Assert.IsTrue(true);
}
}
}
Related
I recorded an Espresso test using the recorder in Android Studio 4.2.2, which included a single assertion that a text field on my MainActivity UI was showing with the correct text string. I then saved this to SplashActivityTest.java:
public class SplashActivityTest {
#Rule
public ActivityTestRule<SplashActivity> mActivityTestRule = new ActivityTestRule<>(SplashActivity.class);
#Before
public void registerIdlingResource() {
IdlingRegistry.getInstance().register(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#After
public void unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#Test
public void splashActivityTest() {
ViewInteraction textView = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView.check(matches(isDisplayed()));
ViewInteraction textView2 = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView2.check(matches(withText("My Playlists")));
}
}
I added use of the Idling registry to this class because in my app what actually happens is a Splash screen is the launcher activity, which then launches the activity that loads the UI that I want to test.
I have this code:
// Necessary for automated tests, decrement handled in MainActivity.onResume()
CountingIdlingResourceSingleton.increment();
In the onCreate() method of SplashActivity and this code:
// Necessary for automated tests - increment is done in SplashActivity.onCreate()
CountingIdlingResourceSingleton.decrement();
At the end of onResume() in MainActivity.
The above code runs flawlessly, the test succeeds. Yay.
However, I get a deprecation warning on my use of ActivityTestRule, in favor of using an ActivityScenarioRule instead of ActivityTestRule (kind of interesting since use of that API was what was generated by the Espresso recorder in the latest 4.2.2 Android Studio, but that's the subject of a different post!).
So I change it:
public class SplashActivityTest {
#Rule
public ActivityScenarioRule<SplashActivity> mActivityTestRule = new ActivityScenarioRule<>(SplashActivity.class);
#Before
public void registerIdlingResource() {
IdlingRegistry.getInstance().register(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#After
public void unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(CountingIdlingResourceSingleton.espressoIdlingResource);
}
#Test
public void splashActivityTest() {
ViewInteraction textView = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView.check(matches(isDisplayed()));
ViewInteraction textView2 = onView(
allOf(withId(R.id.playlistText), withText("My Playlists"),
withParent(withParent(withId(R.id.nav_host_fragment))),
isDisplayed()));
textView2.check(matches(withText("My Playlists")));
}
}
Now it no longer runs flawlessly. My app starts, the application class runs, but the launcher class never is called. Instead I get:
java.lang.AssertionError: Activity never becomes requested state "[DESTROYED, CREATED, STARTED, RESUMED]" (last lifecycle transition = "PRE_ON_CREATE")
Why? What do I need to do differently to insure that my normal launcher activity is called?
I'm currently building a Xamarin.Forms project using MVVMCross. In order to test my platform specific code I am using Nunit.Xamarin which features an app that run tests on device.
This test app is a forms app but doesn't use MVVMCross and I haven't had any luck setting it up to use MVVMCross due to the fact the Application class loads an App of type NUnit.Runner.App whereas MVVMCross requires MvxFormsApp.
I want to test this class the saves and loads user data from an SQLite Database:
public class DataStorageService : IDataStorageService
{
private readonly SQLiteConnection _connection;
public User UserData
{
get { return _connection.Table<User>().FirstOrDefault(); }
set { _connection.InsertOrReplace(value); }
}
public DataStorageService(IMvxSqliteConnectionFactory factory)
{
_connection = factory.GetConnection(DataStorageConstants.LocalDatabaseName);
_connection.CreateTable<User>();
}
}
I want to actually test that it saves and loads from a local SQLite database so I don't want to mock the IMvxSqliteConnectionFactory. I tried installing MVVMCross and the SQLite plugin into the project and then passing in the Android implementation of the connection factory but that repeatedly threw a typeloadexception.
Any ideas as to how I can set up this test with MVVMCross (or are there alternatives?) and dependency injection?
It is possible :) The important stuff happens in the MvxSplashScreenActivity. The MvxFormsApp is basically empty. So we don't have to care. Example Code: https://github.com/smstuebe/stackoverflow-answers/tree/master/mvx-android-test-app
Create a nunit Test app project
Install-Package MvvmCross.StarterPack -Version 4.1.4
Get rid of Views folder
Install the SQLite plugin
Reference your Core project
Install-Package MvvmCross.Forms.Presenter -Version 4.1.4
Remove MainLauncher = true from MainActivity
Adust Setup to return your core project's App
protected override IMvxApplication CreateApp()
{
return new MyApp.Core.App();
}
Change SplashScreen to (source)
[Activity(MainLauncher = true
, Theme = "#style/Theme.Splash"
, NoHistory = true
, ScreenOrientation = ScreenOrientation.Portrait)]
public class SplashScreen
: MvxSplashScreenActivity
{
public SplashScreen()
: base(Resource.Layout.SplashScreen)
{
}
private bool _isInitializationComplete;
public override void InitializationComplete()
{
if (!_isInitializationComplete)
{
_isInitializationComplete = true;
StartActivity(typeof(MainActivity));
}
}
protected override void OnCreate(Android.OS.Bundle bundle)
{
Forms.Init(this, bundle);
Forms.ViewInitialized += (object sender, ViewInitializedEventArgs e) =>
{
if (!string.IsNullOrWhiteSpace(e.View.StyleId))
{
e.NativeView.ContentDescription = e.View.StyleId;
}
};
base.OnCreate(bundle);
}
}
Write a test like
[TestFixture]
public class TestClass
{
[Test]
public void TestMethod()
{
var service = Mvx.Resolve<IDataStorageService>();
Assert.IsNull(service.UserData);
}
}
Enjoy the awesomeness of MvvmCross
Added LeakCanary (1.3) to my Application:
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
LeakCanary.install(this);
When I run the Robolectric test suite for my application I get a NullPointerException in LeakCanary.
Caused by: java.lang.NullPointerException
at com.squareup.leakcanary.LeakCanary.isInServiceProcess(LeakCanary.java:165)
at com.squareup.leakcanary.LeakCanary.isInAnalyzerProcess(LeakCanary.java:141)
at com.squareup.leakcanary.LeakCanary.install(LeakCanary.java:52)
at com.squareup.leakcanary.LeakCanary.install(LeakCanary.java:43)
at com.package.application.MyApplication.onCreate(MyApplication.java:50)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:131)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:431)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:224)
I added that Im using Crashlytics to point out that it (and other methods as well) receives the same Application but does not throw any Exceptions.
Wasn't sure if this should be here or on GitHub issues for LeakCanary. Anyone else experiencing this issue?
Converting my comment to the answer.
Robolectric provides way to deal with different initialisations and application test lifecycles through test application.
Here is your application class:
public class <YourAppplication> extends Application {
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
LeakCanary.install(this);
}
}
You should put in test sources in the same package as yours application next class:
public class Test<YourAppplication> extends <YourApplication> {
#Override
public void onCreate() {
}
}
Robolectric will load it instead of your application. As you can see I suppress all static initialisations from your application.
You can find more details here
A simple way to avoid the NullPointerException is to disable LeakCanary for unit tests by specifying the release (no-op) version in the testCompile directive in build.gradle. For instance:
dependencies {
...
testCompile (
'junit:junit:4.12',
'org.robolectric:robolectric:3.0',
'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
)
...
}
Why there is async and sync versions of UserManagerExtensions (like CreateLocalUser and CreateLocalUserAsync) but only async methods on RoleManagerExtensions? How I suppose to add user to a role from my legacy code? There is only AddUserToRoleAsync and I have a deadlock when running it synchronously. AddUserToRoleAsync(userId, role).Result hangs and .ConfigureAwait(false) does nothing as well.
For the RTM release, there will be sync versions, I'm guessing this was just a bug in the RC release.
Here's what code we use internally to implement the sync versions, you can use this in the meantime to safely call the async methods:
static class AsyncHelper {
private static readonly TaskFactory _myTaskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func) {
return _myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
public static void RunSync(Func<Task> func) {
_myTaskFactory.StartNew(func).Unwrap().GetAwaiter().GetResult();
}
}
i just installed the signalr sample (downloaded with nuget)
everything from nuget installed fine and it's a clean project (just to test the sample), yet i get the following error:
throw "SignalR: Connection must be started before data can be sent. Call .start() before .send()";
use package manager
install-package Microsoft.Owin.Host.SystemWeb
and do changes in startup.cs
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(Microsoft.AspNet.SignalR.StockTicker.Startup), "Configuration")]
namespace Microsoft.AspNet.SignalR.StockTicker
{
public static class Startup
{
public static void Configuration(IAppBuilder app)
{
Microsoft.AspNet.SignalR.StockTicker.Startup.ConfigureSignalR(app);
}
public static void ConfigureSignalR(IAppBuilder app)
{
app.MapSignalR();
}
}
}
Replace code in Startup.cs file with the following code block, that will fix the js error hopefully
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(Microsoft.AspNet.SignalR.StockTicker.Startup))]
namespace Microsoft.AspNet.SignalR.StockTicker
{
public static class Startup
{
public static void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
you have first to call,
$.connection.hub.start
for example :
var myConnection = $.connection.myConnection;
$.connection.hub.start({ transport: 'auto' }, function () {
alert('connected');
});
/// now you can do what ever you want.
myConnection.SendHello('Just Testing');
now when you load open the page, you should see the browser message (connected), to make sure that the signalR has established a connection.
You can find a full working demo with source code at :
Example including VS2010 solution
This worked for me first time.