I am setting up unit testing for my Swift project and am having trouble testing a class function that involves updating IBOutlets.
I have a function, validateUrl, which expects a string to be passed, then validates it. If it is valid, it enables a UIButton, if it is invalid, it disables a UIButton. When I run a test that calls this function, the app crashes on the line of code that enables or disables the UIButton.
The storyboard and controllers both has the proper Test target set.
This line of code:
self.submitButton.enabled = true// Enable Submit Button
Spits out this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Try this code to initialize the IbOutlets of your view controller:
let yourStoryboard = UIStoryboard(name: "Your_storyboard", bundle: nil)
yourViewController = yourStoryboard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
yourViewController.loadView() // This line is the key
You have to initiate the view controller using the storyboard. See the documentation here: https://developer.apple.com/library/ios/documentation/uikit/reference/UIStoryboard_Class/index.html#//apple_ref/occ/instm/UIStoryboard/instantiateViewControllerWithIdentifier:
If you initialize the view controller directly, it will not have any connections because the VC itself does not know of the storyboard in this case.
You may need to add the controllers view to a hierarchy prior to testing to force the controller to load the XIB
let localContainer = UIView(frame:someFrame)
let controllerUnderTest = //instantiate your controller
localContainer.addSubview(controllerUnderTest.view)
//at this point you can test outlets
Otherwise your outlets will be nil as they haven't been connected yet.
Testing IBOutlet's is not the best approach, because:
outlets should be considered implementation details, and should be declared as private
outlets are most of the time connected to pure UI components, and unit tests deal with testing the business logic
testing the value injected into the outlet by another function can be considered somewhat as integration testing. You'd also double the unit tests you have to write by having to test the connected/unconnected outlet scenarios.
In your particular case, I'd recommend instead to test the validator function, but first making it independent of the controller class (if it's not already). Having that function as an input->output one also bring other benefits, like increased reusability.
Once you have tested all the possible scenarios for the validator, validating that the outlet correctly behaves it's just a matter of a quick manual testing: just check if the outlet behaves like the validator returned. UI stuff are better candidates for manual testing, as manual testing can catch other details too (like positioning, colors, etc).
However, if you really want to test the outlet behaviour, one technique that falls into the unit testing philosophy is snapshot testing. There are some libraries available for this, I'd recommend the one from https://github.com/uber/ios-snapshot-test-case/.
A solution I'm using to test classes in Swift is to create the outlets in the setUp() method of the test. For example, I have a UIViewController subclass that has a UIImageView as an outlet. I declare an instance of my View controller subclass a property of my test class, & configure it's outlet in the setUp() method by initializing a new UIImageView.
var viewController = ViewController() // property on the test class
override func setUp() {
super.setUp()
viewController.imageView = UIImageView(image: UIImage(named: "Logo")) // create a new UIImageView and set it as the outlet object
}
Any other outlets can similarly be set in the setUp method, and this way you don't even have to instantiate a storyboard (which, for some reason, despite the fact that I was able to instantiate a UIStoryboard object in my tests, the view controller outlets were still nil).
#talzag In your case iboutlets are nil because they are weak variables, They are supposed to deallocate immediately after instantiation.
Related
so i have a parent in controller like this
import Controller from '#ember/controller';
export default class IndexController extends Controller {
#service firebaseApp;
#service fastboot;
#tracked user =false;
async init(){
super.init(...arguments);
if (!this.fastboot.isFastBoot){
const auth = await this.firebaseApp.auth();
auth.onAuthStateChanged((user)=>{
if(user){
this.user = true
} else {
this.user = false
}
})
}
}
then call a component loadData like this
<LoadData #user={{this.user}}/>
the question is how to execute a function inside component loadData when #user change?
Triggering an action when an argument changes is not that well supported by Ember Octane primitives yet. A common approach is to use either #ember/render-modifiers or ember-render-helpers.
#ember/render-modifiers provide a {{did-update}} modifier.
ember-render-helpers provide a {{did-update}} helper. Both the modifier and the helper except a function as first position argument. That function is executed whenever one of the other positional arguments changes.
{{did-update}} modifier is helpful when the function executed needs access to a DOM element. It sets the DOM element, which it is attached to, as an argument on the function when called.
{{did-update}} helper is helpful when the function executed does not need access to a DOM element.
{{! A Glimmer template }}
{{! did-update helper }}
{{did-update this.loadData #user}}
{{! did-update modifier }}
<div class="loading" {{did-update this.showLoadingSpinner #user}} />
The main use case for {{did-update}} modifier is to ease the migration from classical #ember/component to #glimmer/component. In nearly all cases a specific modifier containing the logic, which should be executed, itself is a better solution. It provides better reusability, can be tested in isolation and has clear boundaries to the components in which it is used.
The main use case for {{did-update}} helper is to fill a gap in current Ember Octance programming model. Ember Octance provides an awesome developer experience for derived state thanks to autotracking and native getters. It provides a great experience to modify a DOM element depending on a value. But it does not have great primitives yet to trigger actions like data loading when an argument changes.
The community current experiments with different approaches to fill that gap. It seems to settle on #use decorator and resources as proposed by Chris Garret (pzuraq) in an RFC and in a recent blog post. It's available for experiments as part of ember-could-get-used-to-this package.
The {{did-update}} helper provided by ember-render-helpers is the most established solution to fill that gap until something like resources settle in Ember.
New to testing and React Redux, so I may be conflating a few issues here. I will only present one example, but I have tried many different combinations of mount(), shallow(), instance(), stub, spy and more.
Given a component, where setFooData() updates redux state and Foo.props.data:
const mapDispatchToProps = (dispatch, props) => ({
setFooData(fooId, data) {
dispatch(Actions.setFooData(fooId, data));
},
});
...
return (
<div fooId={this.props.fooId}>
<Foo {...fooProps}/>
</div>
);
I would like to write some tests around the conditions under which setFooData() is called, namely conditions in lifecycle methods like componentDidMount() and componentWillReceiveProps().
Because setFooData() involves server calls and more, and because these tests merely concern the view layer and how the component renders as a result of Foo.props.data being set eventually by setFooData(), setFooData() seems like a good candidate for stub.
Therefore, Enzyme's shallow(), rather than mount(), seems appropriate, correct? In any case, when I try to stub setFooData():
let wrapper = return shallow(<Foo {...props}/>);
let stub = sinon.stub(wrapper.instance(), 'setFooData');
I receive the error:
Attempted to wrap undefined property setFooData as function
Upon inspection, wrapper.instance() yields an object where setFooData() is indeed not defined, but according to other examples, I would think it should be.
Furthermore, setFooData() does exist on wrapper.instance().selector.props, and while let stub = sinon.stub(wrapper.instance().selector.props, 'setFooData'); avoids the error, when I inspect the object setFooData() =/= stub, and the function is not called as per the test.
When I use mount() instead,
let wrapper = mount(<Provider store={store}><Foo {...props}/></Provider>);
let componentDidMountSpy = sinon.spy(Foo.prototype, 'componentDidMount');
let componentWillReceivePropsSpy = sinon.spy(Foo.prototype, 'componentWillReceiveProps');
expect(componentDidMountSpy.called).to.be.true; //passes
expect(componentWillReceivePropsSpy.called).to.be.true; //passes
expect(stub.called).to.be.true; //fails
I receive a different error that appears related to the body of setFooData(), so setFooData() is called but the function is not actually stubbed to prevent its real body from being executed.
Thanks for any help to clarify my understanding.
I think you're taking the hardest path. You should test your component in isolation, not the connected one. If you test the connected component you're making an integration test and double testing that connect indeed works. That's already tested in react-redux for you.
Instead, test your action creators by themselves in unit tests.
Then, export your component as named export without connecting and use the default export for the connect version.
That way you can simply import the pure-React version and pass anything you want as props, in order to make easy assertions afterwards.
If you need to specifically test that something happens in those lifecycle methods, you can call those methods from the instance:
const fakeActionCreator = sinon.spy()
const subject = mount(<MyComponent doSomething={ fakeActionCreator } />)
subject.instance().componentDidMount()
assert.equal(fakeActionCreator.callCount, 1)
I'm new to unit testing so this may be a daft question.
Usinf mvc 4 I have a view which was working fine.
I declared my model at the top and all was fine.
I then extracted my models out into a seperate library and forgot to change the model declaration on one of my views, hence is crashes.
Is there a way to unit test this?
I don't want to do it by the page title of the view as this may change dynamically...
How is this handled normally or is this something not normally tested?
I have a series of tests I run against each View Model, including a test to make sure the expected property names are there. Here is an example:
/// <summary>
/// Check expected properties exist.
/// </summary>
[Test]
public void Check_Expected_Properties_Exist()
{
// Get properties.
PropertyInfo propInfoFirstName = typeof(ViewModels.MyModel).GetProperty("FirstName");
PropertyInfo propInfoLastName = typeof(ViewModels.MyModel).GetProperty("LastName");
// Assert.
Assert.IsNotNull(propInfoFirstName);
Assert.IsNotNull(propInfoLastName);
}
This is just one of a number of test I run, I will write a blog article on this topic and update this answer when it's ready.
I have added another Answer, in case the previous answer is helpful to anyone else.
Take a look at Selnium WebDriver or WatiN. There are plenty of tutorials and how-tos to get you started.
I usually add a very simple test for each method in my controller to check it return a valid ActionResult.
[TestMethod]
public void TestMyController()
{
// Arrange.
var controller = new MyController();
// Act.
var result = controller.MyMethod() as ViewResult;
// Assert.
Assert.IsNotNull(result);
}
I also add a few tests for each View Model, as I have had an issue with these when they were in a separate class library, but this is outside the scope of your question.
I'm trying out MVVM Light, partly inspired by the EventToCommand capabilities which seem to make it easier to handle drag-and-drop from outside my app in the View Model and in the XAML. However I am a confused by how to unit test the RelayCommand. My RelayCommand is declared simply
public RelayCommand<DragEventArgs> DropFile { get; private set; }
and then the functionality is assigned within the ViewModel constructor, not inline but using a method on the ViewModel
this.DropFile = new RelayCommand<DragEventArgs>(dropFileHandler);
When I'm writing a unit test for the DropFile RelayCommand I cannot see what to call? Should I be calling
testTarget.DropFile.Execute(params)
and how does one construct the params since DragEventArgs has only an empty constructor, and its key properties are just getters not setters?
This is true for standard commands as well as the MVVM-Light specific relay commands.
logic that needs to be unit testable should be implemented in the viewmodel as a method and then called from the command.
whats left in the command should be logic to extract information from the UI, i.e. converting the parameter to the appropriate type and passing it on.
This way the viewmodel as an entity is unit testable, the commands are kept very thin, everyones happy =].
N.B. If you want to be particularly strict with your unit testing, the conversion should happen in the Method of the ViewModel, but typically so long as it can handle a null parameter then your all set which is why I grow lazy.
Hope that helps
I'm trying to unit test a controller that stuffs data into a ViewData. All our views require similar data (Customer info which is derived from the url). So instead of putting the call into every single controller method, the original developers chose to put this ViewData stuffing into the OnActionExecuting event.
Of course, when you invoke the controller's action from a unit test, OnActionExecuting doesn't fire. (Thanks MVC Team!)
So I tried creating a custom view engine and having it stuff the customer data into the controllerContext when the view is requested. This works fine in a browser, but my viewEngine is ignored when I run this test. No amount of ViewEngines.Add(new funkyViewEngine) has any effect.
[TestMethod()]
public void LoginTest()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new FunkyViewEngine());
UserController target = new UserController();
target.SetStructureMap(); <--sets us to use the test repo
target.ControllerContext.HttpContext = MVCHelpers.FakeHttpContext("https://customersubdomain.ourdomain.com"); <--moq magic
var actual = target.Login();
Assert.IsTrue(actual.GetType().IsAssignableFrom(typeof(System.Web.Mvc.ViewResult)));
var vr = actual as ViewResult;
Assert.IsTrue(vr.ViewData.Community() != null); <--"Community" should be set by viewengine
Assert.IsTrue(vr.ViewData.Community().Subdomain == "customersubdomain.ourdomain");
Assert.IsTrue(vr.ViewData.Community().CanRegister);
}
Is there any hope here? How do I either 1) create a method that gets called on controller execution BOTH in the browser and the unit framework or 2) get the unit framework to invoke my view engine.
Sorry for your frustration. The reason why you are seeing OnActionExecuting not being called when you directly call your action method from the unit test is because that's not how things work in MVC.
The request gets executed via a "pipeline", which as far as this area is concerned consists of the ControllerActionInvoker. This class is responsible for:
Finding the action method
Invoking action filters' OnActionExecuting method (note: your controller class is also an action filter)
Calling the action method itself
Invoking the action filters' OnActionExecuted method
Handling the result (e.g. finding the view and rendering it)
In your unit test you are directly invoking step 3. and skipping all the other steps. In a unit test, it is your responsibility to call any setup code required for your action to work.
However, this does not mean you should now write unit tests that use the ControllerActionInvoker to execute the entire pipeline. We (the MVC team) have already verified that all the pieces work together.
Instead, you should test your specific application code. In this case, you might consider having the following unit tests:
A test that verifies that given some Url calling OnActionExecuting on your controller puts the right Customer object into ViewData
A test that verifies that given some Customer object present in ViewData your action method returns the appropriate result
My last point is that you should keep the functionality in OnActionExecuting. A custom view engine is definetely the wrong place for it.
Not an answer you're probably looking for, but I'm using a custom MvcHandler to achieve the same goal (getting customer from URL in multi-tenant app). ViewEngine doesn't sound like a good place for this kind of logic to me...
My custom handler looks more or less like this:
public class AccountMvcHandler : MvcHandler
{
public Account Account { get; private set; }
protected override IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
{
return base.BeginProcessRequest(httpContext, callback, state);
}
protected override IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
{
string accountName = this.RequestContext.RouteData.GetRequiredString("account");
Account = ServiceFactory.GetService<ISecurityService>().GetAccount(accountName);
return base.BeginProcessRequest(httpContext, callback, state);
}
}