diff --git src/wp-includes/widgets.php src/wp-includes/widgets.php
index aed3cd8..d41ce31 100644
--- src/wp-includes/widgets.php
+++ src/wp-includes/widgets.php
@@ -214,20 +214,24 @@ class WP_Widget {
 		$settings = $this->get_settings();
 		$empty = true;
 
-		if ( is_array($settings) ) {
-			foreach ( array_keys($settings) as $number ) {
-				if ( is_numeric($number) ) {
-					$this->_set($number);
-					$this->_register_one($number);
+		// When $settings is an array-like object, get an intrinsic array for use with array_keys().
+		if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {
+			$settings = $settings->getArrayCopy();
+		}
+
+		if ( is_array( $settings ) ) {
+			foreach ( array_keys( $settings ) as $number ) {
+				if ( is_numeric( $number ) ) {
+					$this->_set( $number );
+					$this->_register_one( $number );
 					$empty = false;
 				}
 			}
 		}
 
 		if ( $empty ) {
-			// If there are none, we register the widget's existence with a
-			// generic template
-			$this->_set(1);
+			// If there are none, we register the widget's existence with a generic template.
+			$this->_set( 1 );
 			$this->_register_one();
 		}
 	}
@@ -294,15 +298,16 @@ class WP_Widget {
 	 * }
 	 */
 	public function display_callback( $args, $widget_args = 1 ) {
-		if ( is_numeric($widget_args) )
+		if ( is_numeric( $widget_args ) ) {
 			$widget_args = array( 'number' => $widget_args );
+		}
 
 		$widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
 		$this->_set( $widget_args['number'] );
-		$instance = $this->get_settings();
+		$instances = $this->get_settings();
 
-		if ( array_key_exists( $this->number, $instance ) ) {
-			$instance = $instance[$this->number];
+		if ( isset( $instances[ $this->number ] ) ) {
+			$instance = $instances[ $this->number ];
 
 			/**
 			 * Filter the settings for a particular widget instance.
@@ -424,6 +429,7 @@ class WP_Widget {
 	 * @access public
 	 *
 	 * @param int|array $widget_args Widget instance number or array of widget arguments.
+	 * @return string|null
 	 */
 	public function form_callback( $widget_args = 1 ) {
 		if ( is_numeric($widget_args) )
@@ -516,20 +522,22 @@ class WP_Widget {
 	 */
 	public function get_settings() {
 
-		$settings = get_option($this->option_name);
+		$settings = get_option( $this->option_name );
 
-		if ( false === $settings && isset($this->alt_option_name) )
-			$settings = get_option($this->alt_option_name);
+		if ( false === $settings && isset( $this->alt_option_name ) ) {
+			$settings = get_option( $this->alt_option_name );
+		}
 
-		if ( !is_array($settings) )
+		if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) {
 			$settings = array();
+		}
 
-		if ( !empty($settings) && !array_key_exists('_multiwidget', $settings) ) {
-			// old format, convert if single widget
-			$settings = wp_convert_widget_settings($this->id_base, $this->option_name, $settings);
+		if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) {
+			// Old format, convert if single widget.
+			$settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings );
 		}
 
-		unset($settings['_multiwidget'], $settings['__i__']);
+		unset( $settings['_multiwidget'], $settings['__i__'] );
 		return $settings;
 	}
 }
diff --git tests/phpunit/tests/widgets.php tests/phpunit/tests/widgets.php
index f84ba3e..0fe1667 100644
--- tests/phpunit/tests/widgets.php
+++ tests/phpunit/tests/widgets.php
@@ -1,33 +1,48 @@
 <?php
 
 /**
- * Test widget template tags
+ * Test functions and classes for widgets and sidebars.
  *
  * @group widgets
  */
 class Tests_Widgets extends WP_UnitTestCase {
 
-	function test_register_widget_core_widget() {
+	function clean_up_global_scope() {
+		global $wp_widget_factory, $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
 
-		global $wp_widget_factory;
-
-		unregister_widget( 'WP_Widget_Search' );
-		register_widget( 'WP_Widget_Search' );
-
-		$this->assertTrue( isset( $wp_widget_factory->widgets['WP_Widget_Search'] ) );
+		$wp_registered_sidebars = array();
+		$wp_registered_widgets = array();
+		$wp_registered_widget_controls = array();
+		$wp_registered_widget_updates = array();
+		$wp_widget_factory->widgets = array();
 
+		parent::clean_up_global_scope();
 	}
 
-	function test_unregister_widget_core_widget() {
+	function tearDown() {
+		global $wp_customize;
+		$wp_customize = null;
+		parent::tearDown();
+	}
 
+	/**
+	 * @see register_widget()
+	 * @see unregister_widget()
+	 */
+	function test_register_and_unregister_widget_core_widget() {
 		global $wp_widget_factory;
 
-		unregister_widget( 'WP_Widget_Search' );
-
-		$this->assertFalse( isset( $wp_widget_factory->widgets['WP_Widget_Search'] ) );
+		$widget_class = 'WP_Widget_Search';
+		register_widget( $widget_class );
+		$this->assertArrayHasKey( $widget_class, $wp_widget_factory->widgets );
 
+		unregister_widget( $widget_class );
+		$this->assertArrayNotHasKey( $widget_class, $wp_widget_factory->widgets );
 	}
 
+	/**
+	 * @see register_sidebars()
+	 */
 	function test_register_sidebars_single() {
 
 		global $wp_registered_sidebars;
@@ -38,41 +53,249 @@ class Tests_Widgets extends WP_UnitTestCase {
 
 	}
 
+	/**
+	 * @see register_sidebars()
+	 */
 	function test_register_sidebars_multiple() {
 
 		global $wp_registered_sidebars;
 
+		$result = array();
 		$num = 3;
 		$id_base = 'WP Unit Test';
 		register_sidebars( $num, array( 'name' => $id_base . ' %d' ) );
 
 		$names = wp_list_pluck( $wp_registered_sidebars, 'name' );
 		for ( $i = 1; $i <= $num; $i++ ) {
-			if ( in_array( "$id_base $i", $names ) )
+			if ( in_array( "$id_base $i", $names ) ) {
 				$result[] = true;
+			}
 		}
 
 		$this->assertEquals( $num, count( $result ) );
 
 	}
 
-	function test_register_sidebar() {
+	/**
+	 * @see register_sidebar
+	 * @see unregister_sidebar
+	 */
+	function test_register_and_unregister_sidebar() {
 
 		global $wp_registered_sidebars;
 
-		register_sidebar( array( 'id' => 'wp-unit-test' ) );
+		$sidebar_id = 'wp-unit-test';
+		register_sidebar( array( 'id' => $sidebar_id ) );
+		$this->assertArrayHasKey( $sidebar_id, $wp_registered_sidebars );
 
-		$this->assertTrue( isset( $wp_registered_sidebars['wp-unit-test'] ) );
+		unregister_sidebar( $sidebar_id );
+		$this->assertArrayNotHasKey( 'wp-unit-test', $wp_registered_sidebars );
+	}
 
+	/**
+	 * @see WP_Widget_Search::form()
+	 */
+	function test_wp_widget_search_form() {
+		$widget = new WP_Widget_Search( 'foo', 'Foo' );
+		ob_start();
+		$args = array(
+			'before_widget' => '<section>',
+			'after_widget' => "</section>\n",
+			'before_title' => '<h2>',
+			'after_title' => "</h2>\n",
+		);
+		$instance = array( 'title' => 'Buscar' );
+		$widget->_set( 2 );
+		$widget->widget( $args, $instance );
+		$output = ob_get_clean();
+		$this->assertNotContains( 'no-options-widget', $output );
+		$this->assertContains( '<h2>Buscar</h2>', $output );
+		$this->assertContains( '<section>', $output );
+		$this->assertContains( '</section>', $output );
 	}
 
-	function test_unregister_sidebar() {
+	/**
+	 * @see WP_Widget::form()
+	 */
+	function test_wp_widget_form() {
+		$widget = new WP_Widget( 'foo', 'Foo' );
+		ob_start();
+		$retval = $widget->form( array() );
+		$output = ob_get_clean();
+		$this->assertEquals( 'noform', $retval );
+		$this->assertContains( 'no-options-widget', $output );
+	}
 
-		global $wp_registered_sidebars;
+	/**
+	 * @see WP_Widget::__construct()
+	 */
+	function test_wp_widget_constructor() {
+		$id_base = 'foo';
+		$name = 'Foo';
+		$foo_widget = new WP_Widget( $id_base, $name );
+
+		$this->assertEquals( $id_base, $foo_widget->id_base );
+		$this->assertEquals( $name, $foo_widget->name );
+		$this->assertEquals( "widget_{$id_base}", $foo_widget->option_name );
+		$this->assertArrayHasKey( 'classname', $foo_widget->widget_options );
+		$this->assertEquals( "widget_{$id_base}", $foo_widget->widget_options['classname'] );
+		$this->assertArrayHasKey( 'id_base', $foo_widget->control_options );
+		$this->assertEquals( $id_base, $foo_widget->control_options['id_base'] );
+
+		$id_base = 'bar';
+		$name = 'Bar';
+		$widget_options = array(
+			'classname' => 'bar_classname',
+		);
+		$control_options = array(
+			'id_base' => 'bar_id_base',
+		);
+		$bar_widget = new WP_Widget( $id_base, $name, $widget_options, $control_options );
+		$this->assertEquals( $widget_options['classname'], $bar_widget->widget_options['classname'] );
+		$this->assertEquals( $control_options['id_base'], $bar_widget->control_options['id_base'] );
+	}
+
+	/**
+	 * @see WP_Widget::get_field_name()
+	 */
+	function test_wp_widget_get_field_name() {
+		$widget = new WP_Widget( 'foo', 'Foo' );
+		$widget->_set( 2 );
+		$this->assertEquals( 'widget-foo[2][title]', $widget->get_field_name( 'title' ) );
+	}
+
+	/**
+	 * @see WP_Widget::get_field_id()
+	 */
+	function test_wp_widget_get_field_id() {
+		$widget = new WP_Widget( 'foo', 'Foo' );
+		$widget->_set( 2 );
+		$this->assertEquals( 'widget-foo-2-title', $widget->get_field_id( 'title' ) );
+	}
+
+	/**
+	 * @see WP_Widget::_register()
+	 */
+	function test_wp_widget__register() {
+		global $wp_registered_widgets;
+
+		$settings = get_option( 'widget_search' );
+		unset( $settings['_multiwidget'] );
+		$this->assertArrayHasKey( 2, $settings );
+
+		$this->assertEmpty( $wp_registered_widgets );
+		wp_widgets_init();
 
-		unregister_sidebar( 'sidebar-1' );
+		// Note: We cannot use array_keys() here because $settings could be an ArrayIterator
+		foreach ( $settings as $widget_number => $instance ) {
+			$widget_id = "search-$widget_number";
+			$this->assertArrayHasKey( $widget_id, $wp_registered_widgets );
+		}
+	}
+
+	// @todo test WP_Widget::display_callback()
+
+	/**
+	 * @see WP_Widget::is_preview()
+	 */
+	function test_wp_widget_is_preview() {
+		global $wp_customize;
+
+		$widget = new WP_Widget( 'foo', 'Foo' );
 
-		$this->assertFalse( isset( $wp_registered_sidebars['sidebar-1'] ) );
+		$this->assertEmpty( $wp_customize );
+		$this->assertFalse( $widget->is_preview() );
 
+		wp_set_current_user( $this->factory->user->create( array( 'role' => 'administrator' ) ) );
+		require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
+		$wp_customize = new WP_Customize_Manager();
+		$wp_customize->start_previewing_theme();
+
+		$this->assertTrue( $widget->is_preview() );
+	}
+
+	// @todo test WP_Widget::update_callback()
+	// @todo test WP_Widget::form_callback()
+	// @todo test WP_Widget::_register_one()
+
+	/**
+	 * @see WP_Widget::get_settings()
+	 */
+	function test_wp_widget_get_settings() {
+		global $wp_registered_widgets;
+
+		$option_value = get_option( 'widget_search' );
+		$this->assertArrayHasKey( '_multiwidget', $option_value );
+		$this->assertEquals( 1, $option_value['_multiwidget'] );
+		$this->assertArrayHasKey( 2, $option_value );
+		$instance = $option_value[2];
+		$this->assertInternalType( 'array', $instance );
+		$this->assertArrayHasKey( 'title', $instance );
+		unset( $option_value['_multiwidget'] );
+
+		wp_widgets_init();
+
+		/** @var WP_Widget_Search $wp_widget_search */
+		$wp_widget_search = $wp_registered_widgets['search-2']['callback'][0];
+		$settings = $wp_widget_search->get_settings();
+		// @todo $this->assertArrayNotHasKey( '_multiwidget', $settings ); ?
+		$this->assertArrayHasKey( 2, $settings );
+
+		foreach ( $option_value as $widget_number => $instance ) {
+			$this->assertEquals( $settings[ $widget_number ], $option_value[ $widget_number ] );
+		}
 	}
+
+	/**
+	 * @see WP_Widget::save_settings()
+	 */
+	function test_wp_widget_save_settings() {
+		global $wp_registered_widgets;
+
+		wp_widgets_init();
+
+		/** @var WP_Widget_Search $wp_widget_search */
+		$wp_widget_search = $wp_registered_widgets['search-2']['callback'][0];
+
+		$settings = $wp_widget_search->get_settings();
+		$overridden_title = 'Unit Tested';
+
+		/*
+		 * Note that if a plugin is filtering $settings to be an ArrayIterator,
+		 * then doing this:
+		 *     $settings[2]['title'] = $overridden_title;
+		 * Will fail with this:
+		 * > Indirect modification of overloaded element of X has no effect.
+		 * So this is why the value must be obtained.
+		 */
+		$instance = $settings[2];
+		$instance['title'] = $overridden_title;
+		$settings[2] = $instance;
+
+		$wp_widget_search->save_settings( $settings );
+
+		$option_value = get_option( $wp_widget_search->option_name );
+		$this->assertArrayHasKey( '_multiwidget', $option_value );
+		$this->assertEquals( $overridden_title, $option_value[2]['title'] );
+	}
+
+	/**
+	 * @see WP_Widget::save_settings()
+	 */
+	function test_wp_widget_save_settings_delete() {
+		global $wp_registered_widgets;
+
+		wp_widgets_init();
+
+		/** @var WP_Widget_Search $wp_widget_search */
+		$wp_widget_search = $wp_registered_widgets['search-2']['callback'][0];
+
+		$settings = $wp_widget_search->get_settings();
+		$this->assertArrayHasKey( 2, $settings );
+		unset( $settings[2] );
+		$wp_widget_search->save_settings( $settings );
+		$option_value = get_option( $wp_widget_search->option_name );
+		$this->assertArrayNotHasKey( 2, $option_value );
+	}
+
 }
